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:
@@ -0,0 +1,324 @@
|
||||
(function cloudMailProviderModule(root, factory) {
|
||||
root.MultiPageBackgroundCloudMailProvider = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createCloudMailProviderModule() {
|
||||
function createCloudMailProvider(deps = {}) {
|
||||
const {
|
||||
addLog = async () => {},
|
||||
buildCloudMailHeaders,
|
||||
CLOUD_MAIL_DEFAULT_PAGE_SIZE = 20,
|
||||
CLOUD_MAIL_GENERATOR = 'cloudmail',
|
||||
CLOUD_MAIL_PROVIDER = 'cloudmail',
|
||||
fetchImpl = typeof fetch === 'function' ? fetch.bind(globalThis) : null,
|
||||
getCloudMailTokenFromResponse,
|
||||
getState = async () => ({}),
|
||||
joinCloudMailUrl,
|
||||
normalizeCloudMailAddress,
|
||||
normalizeCloudMailBaseUrl,
|
||||
normalizeCloudMailDomain,
|
||||
normalizeCloudMailDomains,
|
||||
normalizeCloudMailMailApiMessages,
|
||||
pickVerificationMessageWithTimeFallback,
|
||||
setEmailState = async () => {},
|
||||
setPersistentSettings = async () => {},
|
||||
sleepWithStop = async () => {},
|
||||
throwIfStopped = () => {},
|
||||
} = deps;
|
||||
|
||||
function getCloudMailConfig(state = {}) {
|
||||
return {
|
||||
baseUrl: normalizeCloudMailBaseUrl(state.cloudMailBaseUrl),
|
||||
adminEmail: String(state.cloudMailAdminEmail || '').trim(),
|
||||
adminPassword: String(state.cloudMailAdminPassword || ''),
|
||||
token: String(state.cloudMailToken || '').trim(),
|
||||
receiveMailbox: normalizeCloudMailReceiveMailbox(state.cloudMailReceiveMailbox),
|
||||
domain: normalizeCloudMailDomain(state.cloudMailDomain),
|
||||
domains: normalizeCloudMailDomains(state.cloudMailDomains),
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeCloudMailReceiveMailbox(value = '') {
|
||||
const normalized = normalizeCloudMailAddress(value);
|
||||
if (!normalized) return '';
|
||||
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(normalized) ? normalized : '';
|
||||
}
|
||||
|
||||
function resolveCloudMailPollTargetEmail(state = {}, pollPayload = {}, config = getCloudMailConfig(state)) {
|
||||
const configuredReceiveMailbox = normalizeCloudMailReceiveMailbox(config.receiveMailbox);
|
||||
const mailProvider = String(state?.mailProvider || '').trim().toLowerCase();
|
||||
const emailGenerator = String(state?.emailGenerator || '').trim().toLowerCase();
|
||||
const shouldPreferConfiguredReceiveMailbox = mailProvider === CLOUD_MAIL_PROVIDER
|
||||
&& emailGenerator !== CLOUD_MAIL_GENERATOR;
|
||||
if (shouldPreferConfiguredReceiveMailbox && configuredReceiveMailbox) {
|
||||
return configuredReceiveMailbox;
|
||||
}
|
||||
|
||||
const requestedTarget = normalizeCloudMailReceiveMailbox(pollPayload.targetEmail);
|
||||
if (requestedTarget) {
|
||||
return requestedTarget;
|
||||
}
|
||||
|
||||
return normalizeCloudMailReceiveMailbox(state.email);
|
||||
}
|
||||
|
||||
function ensureCloudMailConfig(state, options = {}) {
|
||||
const { requireToken = false, requireCredentials = false, requireDomain = false } = options;
|
||||
const config = getCloudMailConfig(state);
|
||||
if (!config.baseUrl) {
|
||||
throw new Error('Cloud Mail 服务地址为空或格式无效。');
|
||||
}
|
||||
if (requireCredentials && (!config.adminEmail || !config.adminPassword)) {
|
||||
throw new Error('Cloud Mail 缺少管理员邮箱或密码。');
|
||||
}
|
||||
if (requireToken && !config.token) {
|
||||
throw new Error('Cloud Mail 尚未获取到身份令牌,请先生成 Token。');
|
||||
}
|
||||
if (requireDomain && !config.domain) {
|
||||
throw new Error('Cloud Mail 域名为空或格式无效。');
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
async function requestCloudMailJson(config, path, options = {}) {
|
||||
if (!fetchImpl) {
|
||||
throw new Error('Cloud Mail 当前运行环境不支持 fetch。');
|
||||
}
|
||||
const {
|
||||
method = 'POST',
|
||||
payload,
|
||||
timeoutMs = 20000,
|
||||
requireToken = true,
|
||||
} = options;
|
||||
const url = joinCloudMailUrl(config.baseUrl, path);
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(new Error('timeout')), timeoutMs);
|
||||
let response;
|
||||
try {
|
||||
response = await fetchImpl(url, {
|
||||
method,
|
||||
headers: buildCloudMailHeaders(config, {
|
||||
json: payload !== undefined,
|
||||
token: requireToken ? undefined : '',
|
||||
}),
|
||||
body: payload !== undefined ? JSON.stringify(payload) : undefined,
|
||||
signal: controller.signal,
|
||||
});
|
||||
} catch (err) {
|
||||
const errorMessage = err?.name === 'AbortError'
|
||||
? `Cloud Mail 请求超时(>${Math.round(timeoutMs / 1000)} 秒)`
|
||||
: `Cloud Mail 请求失败:${err.message}`;
|
||||
throw new Error(errorMessage);
|
||||
} finally {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
const text = await response.text();
|
||||
let parsed;
|
||||
try {
|
||||
parsed = text ? JSON.parse(text) : {};
|
||||
} catch {
|
||||
parsed = text;
|
||||
}
|
||||
if (!response.ok) {
|
||||
const payloadError = typeof parsed === 'object' && parsed
|
||||
? (parsed.message || parsed.error || parsed.msg)
|
||||
: '';
|
||||
throw new Error(`Cloud Mail 请求失败:${payloadError || text || `HTTP ${response.status}`}`);
|
||||
}
|
||||
if (parsed && typeof parsed === 'object' && 'code' in parsed && Number(parsed.code) !== 200) {
|
||||
throw new Error(`Cloud Mail 业务错误:${parsed.message || parsed.msg || `code=${parsed.code}`}`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
async function ensureCloudMailToken(state, options = {}) {
|
||||
const { forceRefresh = false } = options;
|
||||
const latestState = state || await getState();
|
||||
const config = ensureCloudMailConfig(latestState, { requireCredentials: true });
|
||||
if (!forceRefresh && config.token) {
|
||||
return { config, token: config.token };
|
||||
}
|
||||
const loginConfig = { ...config, token: '' };
|
||||
const result = await requestCloudMailJson(loginConfig, '/api/public/genToken', {
|
||||
method: 'POST',
|
||||
payload: { email: config.adminEmail, password: config.adminPassword },
|
||||
requireToken: false,
|
||||
});
|
||||
const token = getCloudMailTokenFromResponse(result);
|
||||
if (!token) {
|
||||
throw new Error('Cloud Mail 未返回可用 Token。');
|
||||
}
|
||||
await setPersistentSettings({ cloudMailToken: token });
|
||||
return { config: { ...config, token }, token };
|
||||
}
|
||||
|
||||
function generateCloudMailAliasLocalPart() {
|
||||
const letters = 'abcdefghijklmnopqrstuvwxyz';
|
||||
const digits = '0123456789';
|
||||
const chars = [];
|
||||
for (let i = 0; i < 6; i++) chars.push(letters[Math.floor(Math.random() * letters.length)]);
|
||||
for (let i = 0; i < 4; i++) chars.push(digits[Math.floor(Math.random() * digits.length)]);
|
||||
for (let i = chars.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[chars[i], chars[j]] = [chars[j], chars[i]];
|
||||
}
|
||||
return chars.join('');
|
||||
}
|
||||
|
||||
async function fetchCloudMailAddress(state, options = {}) {
|
||||
throwIfStopped();
|
||||
const latestState = state || await getState();
|
||||
const { config } = await ensureCloudMailToken(latestState);
|
||||
const ensuredConfig = ensureCloudMailConfig({ ...latestState, cloudMailToken: config.token }, {
|
||||
requireToken: true,
|
||||
requireDomain: true,
|
||||
});
|
||||
const requestedLocal = String(options.localPart || options.name || '').trim().toLowerCase()
|
||||
|| generateCloudMailAliasLocalPart();
|
||||
const address = `${requestedLocal}@${ensuredConfig.domain}`.toLowerCase();
|
||||
const payload = { list: [{ email: address }] };
|
||||
try {
|
||||
await requestCloudMailJson(ensuredConfig, '/api/public/addUser', { method: 'POST', payload });
|
||||
} catch (err) {
|
||||
if (/token|unauthor|401/i.test(String(err?.message || ''))) {
|
||||
const refreshed = await ensureCloudMailToken(latestState, { forceRefresh: true });
|
||||
await requestCloudMailJson(refreshed.config, '/api/public/addUser', { method: 'POST', payload });
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
await setEmailState(address);
|
||||
await addLog(`Cloud Mail:已生成 ${address}`, 'ok');
|
||||
return address;
|
||||
}
|
||||
|
||||
function summarizeCloudMailMessagesForLog(messages) {
|
||||
return (messages || [])
|
||||
.slice()
|
||||
.sort((left, right) => {
|
||||
const leftTime = Date.parse(left.receivedDateTime || '') || 0;
|
||||
const rightTime = Date.parse(right.receivedDateTime || '') || 0;
|
||||
return rightTime - leftTime;
|
||||
})
|
||||
.slice(0, 3)
|
||||
.map((message) => {
|
||||
const receivedAt = message?.receivedDateTime || '未知时间';
|
||||
const sender = message?.from?.emailAddress?.address || '未知发件人';
|
||||
const subject = message?.subject || '(无主题)';
|
||||
const preview = String(message?.bodyPreview || '').replace(/\s+/g, ' ').trim().slice(0, 80);
|
||||
const address = message?.address || '未知地址';
|
||||
return `[${address}] ${receivedAt} | ${sender} | ${subject} | ${preview}`;
|
||||
})
|
||||
.join(' || ');
|
||||
}
|
||||
|
||||
async function listCloudMailMessages(state, options = {}) {
|
||||
const latestState = state || await getState();
|
||||
const { config } = await ensureCloudMailToken(latestState);
|
||||
const address = normalizeCloudMailAddress(options.address);
|
||||
const pageSize = Number(options.limit) || CLOUD_MAIL_DEFAULT_PAGE_SIZE;
|
||||
const pageNum = Number(options.page) || 1;
|
||||
const request = async (currentConfig) => requestCloudMailJson(currentConfig, '/api/public/emailList', {
|
||||
method: 'POST',
|
||||
payload: {
|
||||
toEmail: address || undefined,
|
||||
type: 0,
|
||||
isDel: 0,
|
||||
timeSort: 'desc',
|
||||
num: pageNum,
|
||||
size: pageSize,
|
||||
},
|
||||
});
|
||||
let payload;
|
||||
try {
|
||||
payload = await request(config);
|
||||
} catch (err) {
|
||||
if (/token|unauthor|401/i.test(String(err?.message || ''))) {
|
||||
const refreshed = await ensureCloudMailToken(latestState, { forceRefresh: true });
|
||||
payload = await request(refreshed.config);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
const messages = normalizeCloudMailMailApiMessages(payload).filter((message) => {
|
||||
if (!address) return true;
|
||||
return !message.address || normalizeCloudMailAddress(message.address) === address;
|
||||
});
|
||||
return { config, messages };
|
||||
}
|
||||
|
||||
async function pollCloudMailVerificationCode(step, state, pollPayload = {}) {
|
||||
const latestState = state || await getState();
|
||||
const config = ensureCloudMailConfig(latestState, { requireCredentials: true });
|
||||
const targetEmail = resolveCloudMailPollTargetEmail(latestState, pollPayload, config);
|
||||
const registrationEmail = normalizeCloudMailReceiveMailbox(latestState.email);
|
||||
if (!targetEmail) {
|
||||
throw new Error('Cloud Mail 轮询前缺少目标邮箱地址,请先填写注册邮箱或"邮件接收"邮箱。');
|
||||
}
|
||||
if (registrationEmail && registrationEmail !== targetEmail) {
|
||||
await addLog(`步骤 ${step}:正在轮询 Cloud Mail 收件邮箱(${targetEmail}),注册邮箱为 ${registrationEmail}...`, 'info');
|
||||
} else {
|
||||
await addLog(`步骤 ${step}:正在轮询 Cloud Mail 邮件(${targetEmail})...`, 'info');
|
||||
}
|
||||
const maxAttempts = Number(pollPayload.maxAttempts) || 5;
|
||||
const intervalMs = Number(pollPayload.intervalMs) || 3000;
|
||||
let lastError = null;
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
throwIfStopped();
|
||||
try {
|
||||
const { messages } = await listCloudMailMessages(latestState, {
|
||||
address: targetEmail,
|
||||
limit: pollPayload.limit || CLOUD_MAIL_DEFAULT_PAGE_SIZE,
|
||||
page: pollPayload.page || 1,
|
||||
});
|
||||
const matchResult = pickVerificationMessageWithTimeFallback(messages, {
|
||||
afterTimestamp: pollPayload.filterAfterTimestamp || 0,
|
||||
senderFilters: pollPayload.senderFilters || [],
|
||||
subjectFilters: pollPayload.subjectFilters || [],
|
||||
excludeCodes: pollPayload.excludeCodes || [],
|
||||
});
|
||||
const match = matchResult.match;
|
||||
if (match?.code) {
|
||||
if (matchResult.usedRelaxedFilters) {
|
||||
const fallbackLabel = matchResult.usedTimeFallback ? '宽松匹配 + 时间回退' : '宽松匹配';
|
||||
await addLog(`步骤 ${step}:严格规则未命中,已改用 ${fallbackLabel} 并命中 Cloud Mail 验证码。`, 'warn');
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
code: match.code,
|
||||
emailTimestamp: match.receivedAt || Date.now(),
|
||||
mailId: match.message?.id || '',
|
||||
};
|
||||
}
|
||||
lastError = new Error(`步骤 ${step}:暂未在 Cloud Mail 中找到匹配验证码(${attempt}/${maxAttempts})。`);
|
||||
await addLog(lastError.message, attempt === maxAttempts ? 'warn' : 'info');
|
||||
const sample = summarizeCloudMailMessagesForLog(messages);
|
||||
if (sample) {
|
||||
await addLog(`步骤 ${step}:最近邮件样本:${sample}`, 'info');
|
||||
}
|
||||
} catch (err) {
|
||||
lastError = err;
|
||||
await addLog(`步骤 ${step}:Cloud Mail 轮询失败:${err.message}`, 'warn');
|
||||
}
|
||||
if (attempt < maxAttempts) {
|
||||
await sleepWithStop(intervalMs);
|
||||
}
|
||||
}
|
||||
throw lastError || new Error(`步骤 ${step}:未在 Cloud Mail 中找到新的匹配验证码。`);
|
||||
}
|
||||
|
||||
return {
|
||||
ensureCloudMailConfig,
|
||||
ensureCloudMailToken,
|
||||
fetchCloudMailAddress,
|
||||
getCloudMailConfig,
|
||||
listCloudMailMessages,
|
||||
normalizeCloudMailReceiveMailbox,
|
||||
pollCloudMailVerificationCode,
|
||||
requestCloudMailJson,
|
||||
resolveCloudMailPollTargetEmail,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
createCloudMailProvider,
|
||||
};
|
||||
});
|
||||
@@ -27,6 +27,7 @@
|
||||
'hotmail-api': 'Hotmail(API对接/本地助手)',
|
||||
'luckmail-api': 'LuckMail(API 购邮)',
|
||||
'cloudflare-temp-email': 'Cloudflare Temp Email',
|
||||
'cloudmail': 'Cloud Mail',
|
||||
};
|
||||
return labels[source] || source || '未知来源';
|
||||
}
|
||||
|
||||
@@ -100,6 +100,16 @@
|
||||
const FREE_PHONE_REUSE_PREPARE_MAX_ROUNDS = 10;
|
||||
const PHONE_SMS_FAILURE_SKIP_THRESHOLD = 2;
|
||||
const MAX_ACTIVATION_PRICE_HINTS = 256;
|
||||
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 activationPriceHintsByKey = new Map();
|
||||
let activePhoneVerificationLogStep = null;
|
||||
let activePhoneVerificationLogStepKey = null;
|
||||
@@ -422,6 +432,21 @@
|
||||
return String(value || '').trim() || fallback;
|
||||
}
|
||||
|
||||
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: normalizeCountryId(match.id, 0),
|
||||
label: normalizeCountryLabel(match.label, `Country #${match.id}`),
|
||||
};
|
||||
}
|
||||
|
||||
function normalizePhoneCodeWaitSeconds(value) {
|
||||
const parsed = Math.floor(Number(value));
|
||||
if (!Number.isFinite(parsed) || parsed <= 0) {
|
||||
@@ -1037,14 +1062,19 @@
|
||||
const activationId = String(
|
||||
record.activationId ?? record.id ?? record.activation ?? ''
|
||||
).trim();
|
||||
const countryLabel = String(record.countryLabel || '').trim();
|
||||
const inferredCountry = inferHeroSmsCountryFromPhoneNumber(phoneNumber);
|
||||
const countryId = normalizeCountryId(record.countryId, inferredCountry?.id || HERO_SMS_COUNTRY_ID);
|
||||
const countryLabel = String(
|
||||
record.countryLabel
|
||||
|| (inferredCountry && inferredCountry.id === countryId ? inferredCountry.label : '')
|
||||
).trim();
|
||||
const statusAction = String(record.statusAction || '').trim();
|
||||
return {
|
||||
...(activationId ? { activationId } : {}),
|
||||
phoneNumber,
|
||||
provider: PHONE_SMS_PROVIDER_HERO,
|
||||
serviceCode: String(record.serviceCode || HERO_SMS_SERVICE_CODE).trim() || HERO_SMS_SERVICE_CODE,
|
||||
countryId: normalizeCountryId(record.countryId, HERO_SMS_COUNTRY_ID),
|
||||
countryId,
|
||||
...(countryLabel ? { countryLabel } : {}),
|
||||
successfulUses: normalizeUseCount(record.successfulUses),
|
||||
maxUses: Math.max(1, Math.floor(Number(record.maxUses) || DEFAULT_PHONE_NUMBER_MAX_USES)),
|
||||
@@ -3935,7 +3965,16 @@
|
||||
};
|
||||
}
|
||||
} else {
|
||||
const countryId = normalizeCountryId(activation.countryId, 0);
|
||||
const inferredCountry = inferHeroSmsCountryFromPhoneNumber(activation.phoneNumber);
|
||||
const rawCountryId = normalizeCountryId(activation.countryId, 0);
|
||||
const hasExplicitCountry = Object.prototype.hasOwnProperty.call(activation, 'countryId')
|
||||
&& Number.isFinite(rawCountryId)
|
||||
&& rawCountryId > 0
|
||||
&& !(activation.manualOnly && rawCountryId === HERO_SMS_COUNTRY_ID && inferredCountry?.id && inferredCountry.id !== rawCountryId);
|
||||
const countryId = hasExplicitCountry ? rawCountryId : normalizeCountryId(inferredCountry?.id, rawCountryId);
|
||||
const countryLabel = hasExplicitCountry
|
||||
? activation.countryLabel
|
||||
: (inferredCountry?.label || activation.countryLabel);
|
||||
if (countryId > 0) {
|
||||
const matched = candidates.find((entry) => entry.id === countryId);
|
||||
if (matched) {
|
||||
@@ -3943,7 +3982,7 @@
|
||||
}
|
||||
return {
|
||||
id: countryId,
|
||||
label: normalizeCountryLabel(activation.countryLabel, `Country #${countryId}`),
|
||||
label: normalizeCountryLabel(countryLabel, `Country #${countryId}`),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -4286,7 +4325,11 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
if (normalizeFreePhoneReuseAutoEnabled(state)) {
|
||||
const canPrepareAutomaticFreeReuse = normalizeFreePhoneReuseAutoEnabled(state)
|
||||
&& !freeReusableActivation.manualOnly
|
||||
&& Boolean(String(freeReusableActivation.activationId || '').trim());
|
||||
|
||||
if (canPrepareAutomaticFreeReuse) {
|
||||
await addLog(
|
||||
`步骤 9:准备自动白嫖复用已保存手机号 ${freeReusableActivation.phoneNumber}(${freeReusableActivation.successfulUses + 1}/${freeReusableActivation.maxUses})。`,
|
||||
'info'
|
||||
@@ -6245,6 +6288,7 @@
|
||||
completeSignupPhoneVerificationFlow,
|
||||
finalizeLoginPhoneActivationAfterSuccess,
|
||||
finalizeSignupPhoneActivationAfterSuccess,
|
||||
isPhoneResendBannedNumberError,
|
||||
normalizeActivation,
|
||||
pollPhoneActivationCode,
|
||||
prepareLoginPhoneActivation,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
addLog: rawAddLog = async () => {},
|
||||
chrome,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER = 'cloudmail',
|
||||
completeStepFromBackground,
|
||||
confirmCustomVerificationStepBypass,
|
||||
ensureMail2925MailboxSession,
|
||||
@@ -484,6 +485,7 @@
|
||||
mail.provider === HOTMAIL_PROVIDER
|
||||
|| mail.provider === LUCKMAIL_PROVIDER
|
||||
|| mail.provider === CLOUDFLARE_TEMP_EMAIL_PROVIDER
|
||||
|| mail.provider === CLOUD_MAIL_PROVIDER
|
||||
) {
|
||||
await addLog(`步骤 ${visibleStep}:正在通过 ${mail.label} 轮询验证码...`);
|
||||
} else {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
isTabAlive,
|
||||
LUCKMAIL_PROVIDER,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER = 'cloudmail',
|
||||
resolveVerificationStep,
|
||||
reuseOrCreateTab,
|
||||
sendToContentScript,
|
||||
@@ -238,6 +239,7 @@
|
||||
mail.provider === HOTMAIL_PROVIDER
|
||||
|| mail.provider === LUCKMAIL_PROVIDER
|
||||
|| mail.provider === CLOUDFLARE_TEMP_EMAIL_PROVIDER
|
||||
|| mail.provider === CLOUD_MAIL_PROVIDER
|
||||
) {
|
||||
await addLog(`步骤 4:正在通过 ${mail.label} 轮询验证码...`);
|
||||
} else if (mail.provider === '2925') {
|
||||
@@ -263,6 +265,7 @@
|
||||
HOTMAIL_PROVIDER,
|
||||
LUCKMAIL_PROVIDER,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER,
|
||||
].includes(mail.provider);
|
||||
const signupProfile = buildSignupProfileForVerificationStep();
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
chrome,
|
||||
closeConflictingTabsForSource,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER = 'cloudmail',
|
||||
completeStepFromBackground,
|
||||
confirmCustomVerificationStepBypassRequest,
|
||||
getHotmailVerificationPollConfig,
|
||||
@@ -24,6 +25,7 @@
|
||||
MAIL_2925_VERIFICATION_INTERVAL_MS,
|
||||
MAIL_2925_VERIFICATION_MAX_ATTEMPTS,
|
||||
pollCloudflareTempEmailVerificationCode,
|
||||
pollCloudMailVerificationCode,
|
||||
pollHotmailVerificationCode,
|
||||
pollLuckmailVerificationCode,
|
||||
sendToContentScript,
|
||||
@@ -927,6 +929,13 @@
|
||||
}, cleanPollOverrides, `轮询${getVerificationCodeLabel(step)}验证码邮箱`);
|
||||
return pollCloudflareTempEmailVerificationCode(step, state, timedPoll.payload);
|
||||
}
|
||||
if (mail.provider === CLOUD_MAIL_PROVIDER) {
|
||||
const timedPoll = await applyMailPollingTimeBudget(step, {
|
||||
...getVerificationPollPayload(step, state),
|
||||
...cleanPollOverrides,
|
||||
}, cleanPollOverrides, `轮询${getVerificationCodeLabel(step)}验证码邮箱`);
|
||||
return pollCloudMailVerificationCode(step, state, timedPoll.payload);
|
||||
}
|
||||
|
||||
if (Number(pollOverrides.resendIntervalMs) > 0) {
|
||||
return pollFreshVerificationCodeWithResendInterval(step, state, mail, pollOverrides);
|
||||
|
||||
Reference in New Issue
Block a user