From 8a11b91c5a662bed9f9c990c9590991300c6f4f0 Mon Sep 17 00:00:00 2001
From: QLHazyCoder <2825305047@qq.com>
Date: Sat, 16 May 2026 05:40:04 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8E=A5=E7=A0=81=E9=82=AE?=
=?UTF-8?q?=E7=AE=B1=E7=BB=91=E5=AE=9A=E4=B8=8E=E9=AA=8C=E8=AF=81=E7=A0=81?=
=?UTF-8?q?=E6=8F=90=E4=BA=A4=E8=B6=85=E6=97=B6=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
background.js | 68 ++++++++--
background/verification-flow.js | 16 ++-
cloudflare-temp-email-utils.js | 7 +
data/step-definitions.js | 11 +-
sidepanel/sidepanel.html | 9 +-
sidepanel/sidepanel.js | 122 +++++++++++++++++-
...und-cloudflare-temp-email-settings.test.js | 11 ++
tests/cloudflare-temp-email-provider.test.js | 76 ++++++++++-
tests/cloudflare-temp-email-utils.test.js | 2 +
...dflare-temp-email-random-subdomain.test.js | 39 +++++-
tests/step-definitions-module.test.js | 10 +-
tests/step8-state-timeout-retry.test.js | 6 +
tests/verification-flow-polling.test.js | 51 ++++++++
13 files changed, 394 insertions(+), 34 deletions(-)
diff --git a/background.js b/background.js
index 0f6fb20..3598798 100644
--- a/background.js
+++ b/background.js
@@ -520,6 +520,9 @@ const DEFAULT_LOCAL_CPA_STEP9_MODE = 'submit';
const MAIL_2925_MODE_PROVIDE = 'provide';
const MAIL_2925_MODE_RECEIVE = 'receive';
const DEFAULT_MAIL_2925_MODE = MAIL_2925_MODE_PROVIDE;
+const CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_RECEIVE_MAILBOX = 'receive-mailbox';
+const CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL = 'registration-email';
+const DEFAULT_CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE = CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_RECEIVE_MAILBOX;
const HOTMAIL_SERVICE_MODE_REMOTE = 'remote';
const HOTMAIL_SERVICE_MODE_LOCAL = 'local';
const DEFAULT_HOTMAIL_REMOTE_BASE_URL = '';
@@ -988,6 +991,7 @@ const PERSISTED_SETTING_DEFAULTS = {
cloudflareTempEmailBaseUrl: '',
cloudflareTempEmailAdminAuth: '',
cloudflareTempEmailCustomAuth: '',
+ cloudflareTempEmailLookupMode: DEFAULT_CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE,
cloudflareTempEmailReceiveMailbox: '',
cloudflareTempEmailUseRandomSubdomain: false,
cloudflareTempEmailDomain: '',
@@ -2419,6 +2423,12 @@ function normalizeMail2925Mode(value = '') {
: DEFAULT_MAIL_2925_MODE;
}
+function normalizeCloudflareTempEmailLookupMode(value = '') {
+ return String(value || '').trim().toLowerCase() === CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL
+ ? CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL
+ : DEFAULT_CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE;
+}
+
function normalizeLocalCpaStep9Mode(value = '') {
return String(value || '').trim().toLowerCase() === 'bypass'
? 'bypass'
@@ -2523,6 +2533,7 @@ function getCloudflareTempEmailConfig(state = {}) {
baseUrl: normalizeCloudflareTempEmailBaseUrl(state.cloudflareTempEmailBaseUrl),
adminAuth: String(state.cloudflareTempEmailAdminAuth || ''),
customAuth: String(state.cloudflareTempEmailCustomAuth || ''),
+ lookupMode: normalizeCloudflareTempEmailLookupMode(state.cloudflareTempEmailLookupMode),
receiveMailbox: normalizeCloudflareTempEmailReceiveMailbox(state.cloudflareTempEmailReceiveMailbox),
useRandomSubdomain: Boolean(state.cloudflareTempEmailUseRandomSubdomain),
domain: normalizeCloudflareTempEmailDomain(state.cloudflareTempEmailDomain),
@@ -2542,11 +2553,18 @@ function resolveCloudflareTempEmailPollTargetEmail(state = {}, pollPayload = {},
const emailGenerator = String(state?.emailGenerator || '').trim().toLowerCase();
const shouldPreferConfiguredReceiveMailbox = mailProvider === 'cloudflare-temp-email'
&& emailGenerator !== 'cloudflare-temp-email';
+ const requestedTarget = normalizeCloudflareTempEmailReceiveMailbox(pollPayload.targetEmail);
+ if (
+ shouldPreferConfiguredReceiveMailbox
+ && normalizeCloudflareTempEmailLookupMode(config.lookupMode) === CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL
+ ) {
+ return requestedTarget || normalizeCloudflareTempEmailReceiveMailbox(state.email);
+ }
+
if (shouldPreferConfiguredReceiveMailbox && configuredReceiveMailbox) {
return configuredReceiveMailbox;
}
- const requestedTarget = normalizeCloudflareTempEmailReceiveMailbox(pollPayload.targetEmail);
if (requestedTarget) {
return requestedTarget;
}
@@ -2925,6 +2943,8 @@ function normalizePersistentSettingValue(key, value) {
case 'cloudflareTempEmailAdminAuth':
case 'cloudflareTempEmailCustomAuth':
return String(value || '');
+ case 'cloudflareTempEmailLookupMode':
+ return normalizeCloudflareTempEmailLookupMode(value);
case 'cloudflareTempEmailReceiveMailbox':
return normalizeCloudflareTempEmailReceiveMailbox(value);
case 'cloudflareTempEmailDomain':
@@ -5849,32 +5869,59 @@ async function deleteCloudflareTempEmailMail(config, mailId) {
async function listCloudflareTempEmailMessages(state, options = {}) {
const config = ensureCloudflareTempEmailConfig(state, { requireAdminAuth: true });
const address = normalizeCloudflareTempEmailAddress(options.address);
+ const lookupMode = normalizeCloudflareTempEmailLookupMode(options.lookupMode || config.lookupMode);
+ const originalRecipient = normalizeCloudflareTempEmailReceiveMailbox(options.originalRecipient);
+ const useRegistrationLookup = lookupMode === CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL
+ && Boolean(originalRecipient);
+ const queryAddress = useRegistrationLookup ? '' : address;
const payload = await requestCloudflareTempEmailJson(config, '/admin/mails', {
method: 'GET',
searchParams: {
limit: Number(options.limit) || CLOUDFLARE_TEMP_EMAIL_DEFAULT_PAGE_SIZE,
offset: Number(options.offset) || 0,
- address,
+ address: queryAddress,
},
});
- const messages = normalizeCloudflareTempEmailMailApiMessages(payload).filter((message) => {
+ const normalizedMessages = normalizeCloudflareTempEmailMailApiMessages(payload);
+ const hasOriginalRecipient = normalizedMessages.some((message) => normalizeCloudflareTempEmailReceiveMailbox(message.originalRecipient));
+ const messages = normalizedMessages.filter((message) => {
+ if (useRegistrationLookup) {
+ return normalizeCloudflareTempEmailReceiveMailbox(message.originalRecipient) === originalRecipient;
+ }
if (!address) return true;
return !message.address || normalizeCloudflareTempEmailAddress(message.address) === address;
});
- return { config, messages };
+ return {
+ config,
+ messages,
+ lookupMode,
+ originalRecipient,
+ missingOriginalRecipient: useRegistrationLookup && normalizedMessages.length > 0 && !hasOriginalRecipient,
+ };
}
async function pollCloudflareTempEmailVerificationCode(step, state, pollPayload = {}) {
const config = ensureCloudflareTempEmailConfig(state, { requireAdminAuth: true });
const targetEmail = resolveCloudflareTempEmailPollTargetEmail(state, pollPayload, config);
const registrationEmail = normalizeCloudflareTempEmailReceiveMailbox(state.email);
+ const lookupMode = normalizeCloudflareTempEmailLookupMode(config.lookupMode);
+ const mailProvider = String(state?.mailProvider || '').trim().toLowerCase();
+ const emailGenerator = String(state?.emailGenerator || '').trim().toLowerCase();
+ const useRegistrationLookup = mailProvider === 'cloudflare-temp-email'
+ && emailGenerator !== 'cloudflare-temp-email'
+ && lookupMode === CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL;
+ const originalRecipient = normalizeCloudflareTempEmailReceiveMailbox(pollPayload.targetEmail)
+ || registrationEmail
+ || targetEmail;
if (!targetEmail) {
throw new Error('Cloudflare Temp Email 轮询前缺少目标邮箱地址,请先填写注册邮箱或“邮件接收”邮箱。');
}
- if (registrationEmail && registrationEmail !== targetEmail) {
+ if (useRegistrationLookup) {
+ await addLog(`步骤 ${step}:正在按注册邮箱筛选 Cloudflare Temp Email 邮件(${originalRecipient})...`, 'info');
+ } else if (registrationEmail && registrationEmail !== targetEmail) {
await addLog(`步骤 ${step}:正在轮询 Cloudflare Temp Email 收件邮箱(${targetEmail}),注册邮箱为 ${registrationEmail}...`, 'info');
} else {
await addLog(`步骤 ${step}:正在轮询 Cloudflare Temp Email 邮件(${targetEmail})...`, 'info');
@@ -5886,11 +5933,16 @@ async function pollCloudflareTempEmailVerificationCode(step, state, pollPayload
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
throwIfStopped();
try {
- const { messages } = await listCloudflareTempEmailMessages(state, {
- address: targetEmail,
+ const { messages, missingOriginalRecipient } = await listCloudflareTempEmailMessages(state, {
+ address: useRegistrationLookup ? '' : targetEmail,
+ lookupMode,
+ originalRecipient,
limit: pollPayload.limit || CLOUDFLARE_TEMP_EMAIL_DEFAULT_PAGE_SIZE,
offset: pollPayload.offset || 0,
});
+ if (useRegistrationLookup && missingOriginalRecipient) {
+ throw new Error('Cloudflare Temp Email 当前接口未返回 original_recipient,注册邮箱查信需要部署本扩展作者修改后的 Cloudflare Temp Email,或切回“邮件接收”。');
+ }
const matchResult = pickVerificationMessageWithTimeFallback(messages, {
afterTimestamp: pollPayload.filterAfterTimestamp || 0,
senderFilters: pollPayload.senderFilters || [],
@@ -8058,7 +8110,7 @@ function isStopError(error) {
function isRetryableContentScriptTransportError(error) {
const message = String(typeof error === 'string' ? error : error?.message || '');
- return /back\/forward cache|message channel is closed|Receiving end does not exist|port closed before a response was received|A listener indicated an asynchronous response|did not respond in \d+s|failed to fetch|networkerror|network error|fetch failed|load failed/i.test(message);
+ return /back\/forward cache|message channel is closed|Receiving end does not exist|port closed before a response was received|A listener indicated an asynchronous response|内容脚本\s+\d+(?:\.\d+)?\s*秒内未响应|did not respond in \d+s|failed to fetch|networkerror|network error|fetch failed|load failed/i.test(message);
}
function isStepFetchNetworkRetryableError(error) {
diff --git a/background/verification-flow.js b/background/verification-flow.js
index a7e3a39..8b07c40 100644
--- a/background/verification-flow.js
+++ b/background/verification-flow.js
@@ -467,11 +467,16 @@
async function getResponseTimeoutMsForStep(step, options = {}, fallbackMs = 30000, actionLabel = '') {
const remainingMs = await getRemainingTimeBudgetMs(step, options, actionLabel);
+ const fallbackTimeoutMs = Math.max(1000, Number(fallbackMs) || 1000);
+ const minResponseTimeoutMs = Math.min(
+ fallbackTimeoutMs,
+ Math.max(1000, Number(options.minResponseTimeoutMs) || 1000)
+ );
if (remainingMs === null) {
- return Math.max(1000, Number(fallbackMs) || 1000);
+ return Math.max(minResponseTimeoutMs, fallbackTimeoutMs);
}
- return Math.max(1000, Math.min(Math.max(1000, Number(fallbackMs) || 1000), remainingMs));
+ return Math.max(minResponseTimeoutMs, Math.min(fallbackTimeoutMs, remainingMs));
}
async function applyMailPollingTimeBudget(step, payload, options = {}, actionLabel = '') {
@@ -1105,7 +1110,12 @@
await chrome.tabs.update(signupTabId, { active: true });
const baseResponseTimeoutMs = await getResponseTimeoutMsForStep(
step,
- options,
+ step === 8
+ ? {
+ ...options,
+ minResponseTimeoutMs: Math.max(15000, Number(options.minResponseTimeoutMs) || 0),
+ }
+ : options,
step === 7 ? 45000 : 30000,
`填写${getVerificationCodeLabel(step)}验证码`
);
diff --git a/cloudflare-temp-email-utils.js b/cloudflare-temp-email-utils.js
index e7a8992..75a10bc 100644
--- a/cloudflare-temp-email-utils.js
+++ b/cloudflare-temp-email-utils.js
@@ -327,6 +327,12 @@
row.email,
row.recipient,
]));
+ const originalRecipient = normalizeCloudflareTempEmailAddress(firstNonEmptyString([
+ row.original_recipient,
+ row.originalRecipient,
+ row.original_recipient_email,
+ row.originalRecipientEmail,
+ ]));
const raw = firstNonEmptyString([row.raw, row.source, row.mime, row.message]);
const parsedMime = raw ? extractTextFromMime(raw) : { headers: {}, text: '' };
const subject = decodeMimeEncodedWords(firstNonEmptyString([
@@ -350,6 +356,7 @@
return {
id: firstNonEmptyString([row.id, row.mail_id]),
address,
+ originalRecipient,
addressId: firstNonEmptyString([row.address_id, row.addressId]),
subject,
from: {
diff --git a/data/step-definitions.js b/data/step-definitions.js
index 102f9ac..dbcfbf5 100644
--- a/data/step-definitions.js
+++ b/data/step-definitions.js
@@ -67,11 +67,12 @@
return [
...commonStart,
{ id: id + 2, order: order + 20, key: 'bind-email', title: '绑定邮箱', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'bind-email' },
- { id: id + 3, order: order + 30, key: 'relogin-bound-email', title: '绑定邮箱后刷新 OAuth 并登录(邮箱)', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'oauth-login' },
- { id: id + 4, order: order + 40, key: 'fetch-bound-email-login-code', title: '获取登录验证码(邮箱)', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-verification-code', mailRuleId: 'openai-login-code' },
- { id: id + 5, order: order + 50, key: 'post-bound-email-phone-verification', title: '手机号验证', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'post-login-phone-verification' },
- { id: id + 6, order: order + 60, key: 'confirm-oauth', title: '自动确认 OAuth', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'confirm-oauth' },
- { id: id + 7, order: order + 70, key: 'platform-verify', title: '平台回调验证', sourceId: 'platform-panel', driverId: 'content/platform-panel', command: 'platform-verify' },
+ { id: id + 3, order: order + 30, key: 'fetch-bind-email-code', title: '获取绑定邮箱验证码', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'fetch-bind-email-code', mailRuleId: 'openai-login-code' },
+ { id: id + 4, order: order + 40, key: 'relogin-bound-email', title: '绑定邮箱后刷新 OAuth 并登录(邮箱)', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'oauth-login' },
+ { id: id + 5, order: order + 50, key: 'fetch-bound-email-login-code', title: '获取登录验证码(邮箱)', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-verification-code', mailRuleId: 'openai-login-code' },
+ { id: id + 6, order: order + 60, key: 'post-bound-email-phone-verification', title: '手机号验证', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'post-login-phone-verification' },
+ { id: id + 7, order: order + 70, key: 'confirm-oauth', title: '自动确认 OAuth', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'confirm-oauth' },
+ { id: id + 8, order: order + 80, key: 'platform-verify', title: '平台回调验证', sourceId: 'platform-panel', driverId: 'content/platform-panel', command: 'platform-verify' },
];
}
return [
diff --git a/sidepanel/sidepanel.html b/sidepanel/sidepanel.html
index f41ff69..ad7f900 100644
--- a/sidepanel/sidepanel.html
+++ b/sidepanel/sidepanel.html
@@ -672,7 +672,7 @@
-
+
@@ -699,6 +699,13 @@
data-hide-label="隐藏 Custom Auth" aria-label="显示 Custom Auth" title="显示 Custom Auth">
+
+
查信方式
+
+
+
+
+
邮件接收
= AUTO_RUN_FALLBACK_RISK_WARNING_MIN_RUNS;
}
@@ -2123,6 +2139,30 @@ async function confirmCpaPhoneSignupIfNeeded(options = {}) {
return result.confirmed;
}
+function buildCloudflareTempEmailRegistrationLookupPromptHtml() {
+ const repositoryUrl = escapeHtml(CLOUDFLARE_TEMP_EMAIL_REPOSITORY_URL);
+ return `需要部署本扩展作者修改后的
Cloudflare Temp Email;部署后可支持多线程收码。`;
+}
+
+async function confirmCloudflareTempEmailRegistrationLookupIfNeeded() {
+ if (isCloudflareTempEmailRegistrationLookupPromptDismissed()) {
+ return true;
+ }
+
+ const result = await openConfirmModalWithOption({
+ title: '注册邮箱查信',
+ messageHtml: buildCloudflareTempEmailRegistrationLookupPromptHtml(),
+ confirmLabel: '我已知晓',
+ optionLabel: '不再提醒',
+ });
+
+ if (result.confirmed && result.optionChecked) {
+ setCloudflareTempEmailRegistrationLookupPromptDismissed(true);
+ }
+
+ return result.confirmed;
+}
+
async function openAutoSkipFailuresConfirmModal() {
const result = await openConfirmModalWithOption({
title: '自动重试说明',
@@ -3141,6 +3181,7 @@ function applyCloudflareTempEmailSettingsState(state = {}) {
inputTempEmailAdminAuth.value = state?.cloudflareTempEmailAdminAuth || '';
inputTempEmailCustomAuth.value = state?.cloudflareTempEmailCustomAuth || '';
inputTempEmailReceiveMailbox.value = state?.cloudflareTempEmailReceiveMailbox || '';
+ setCloudflareTempEmailLookupMode(state?.cloudflareTempEmailLookupMode);
if (inputTempEmailUseRandomSubdomain) {
inputTempEmailUseRandomSubdomain.checked = Boolean(state?.cloudflareTempEmailUseRandomSubdomain);
}
@@ -3928,6 +3969,9 @@ function collectSettingsPayload() {
cloudflareTempEmailBaseUrl: normalizeCloudflareTempEmailBaseUrlValue(inputTempEmailBaseUrl.value),
cloudflareTempEmailAdminAuth: inputTempEmailAdminAuth.value,
cloudflareTempEmailCustomAuth: inputTempEmailCustomAuth.value,
+ cloudflareTempEmailLookupMode: typeof getSelectedCloudflareTempEmailLookupMode === 'function'
+ ? getSelectedCloudflareTempEmailLookupMode()
+ : 'receive-mailbox',
cloudflareTempEmailReceiveMailbox: normalizeCloudflareTempEmailReceiveMailboxValue(inputTempEmailReceiveMailbox.value),
cloudflareTempEmailUseRandomSubdomain: Boolean(inputTempEmailUseRandomSubdomain?.checked),
cloudflareTempEmailDomain: selectedCloudflareTempEmailDomain,
@@ -4004,6 +4048,12 @@ function normalizeMail2925Mode(value = '') {
: DEFAULT_MAIL_2925_MODE;
}
+function normalizeCloudflareTempEmailLookupMode(value = '') {
+ return String(value || '').trim().toLowerCase() === CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL
+ ? CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL
+ : DEFAULT_CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE;
+}
+
function normalizeHotmailServiceMode(value = '') {
if (typeof normalizeHotmailServiceModeFromUtils === 'function') {
return normalizeHotmailServiceModeFromUtils(value);
@@ -7579,6 +7629,20 @@ function setMail2925Mode(mode) {
});
}
+function getSelectedCloudflareTempEmailLookupMode() {
+ const activeButton = tempEmailLookupModeButtons.find((button) => button.classList.contains('is-active'));
+ return normalizeCloudflareTempEmailLookupMode(activeButton?.dataset.tempEmailLookupMode);
+}
+
+function setCloudflareTempEmailLookupMode(mode) {
+ const resolvedMode = normalizeCloudflareTempEmailLookupMode(mode);
+ tempEmailLookupModeButtons.forEach((button) => {
+ const active = button.dataset.tempEmailLookupMode === resolvedMode;
+ button.classList.toggle('is-active', active);
+ button.setAttribute('aria-pressed', String(active));
+ });
+}
+
function getSelectedHotmailServiceMode() {
const activeButton = hotmailServiceModeButtons.find((button) => button.classList.contains('is-active'));
return normalizeHotmailServiceMode(activeButton?.dataset.hotmailServiceMode);
@@ -10645,7 +10709,17 @@ function updateMailProviderUI() {
const useCloudMailGenerator = selectedGenerator === 'cloudmail';
const showCloudflareDomain = useEmailGenerator && useCloudflare;
const showCloudflareTempEmailSettings = useCloudflareTempEmailProvider || (useEmailGenerator && useCloudflareTempEmailGenerator);
- const showCloudflareTempEmailReceiveMailbox = useCloudflareTempEmailProvider && !useCloudflareTempEmailGenerator;
+ const showCloudflareTempEmailLookupMode = useCloudflareTempEmailProvider && !useCloudflareTempEmailGenerator;
+ const selectedCloudflareTempEmailLookupMode = typeof getSelectedCloudflareTempEmailLookupMode === 'function'
+ ? getSelectedCloudflareTempEmailLookupMode()
+ : 'receive-mailbox';
+ const cloudflareTempEmailRegistrationLookupMode = typeof CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL === 'string'
+ ? CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL
+ : 'registration-email';
+ const useCloudflareTempEmailRegistrationLookup = showCloudflareTempEmailLookupMode
+ && selectedCloudflareTempEmailLookupMode === cloudflareTempEmailRegistrationLookupMode;
+ const showCloudflareTempEmailReceiveMailbox = showCloudflareTempEmailLookupMode
+ && !useCloudflareTempEmailRegistrationLookup;
const showCloudMailSettings = useCloudMailProvider || (useEmailGenerator && useCloudMailGenerator);
const showCloudMailReceiveMailbox = useCloudMailProvider && !useCloudMailGenerator;
const showCloudMailDomain = useEmailGenerator && useCloudMailGenerator;
@@ -10708,6 +10782,9 @@ function updateMailProviderUI() {
rowTempEmailBaseUrl.style.display = showCloudflareTempEmailSettings ? '' : 'none';
rowTempEmailAdminAuth.style.display = showCloudflareTempEmailSettings ? '' : 'none';
rowTempEmailCustomAuth.style.display = showCloudflareTempEmailSettings ? '' : 'none';
+ if (typeof rowTempEmailLookupMode !== 'undefined' && rowTempEmailLookupMode) {
+ rowTempEmailLookupMode.style.display = showCloudflareTempEmailLookupMode ? '' : 'none';
+ }
rowTempEmailReceiveMailbox.style.display = showCloudflareTempEmailReceiveMailbox ? '' : 'none';
if (rowTempEmailRandomSubdomainToggle) {
rowTempEmailRandomSubdomainToggle.style.display = showCloudflareTempEmailRandomSubdomainToggle ? '' : 'none';
@@ -12521,6 +12598,12 @@ autoStartModal?.addEventListener('click', (event) => {
resolveModalChoice(null);
}
});
+autoStartMessage?.addEventListener('click', (event) => {
+ const link = event.target?.closest?.('a[data-external-url]');
+ if (!link) return;
+ event.preventDefault();
+ openExternalUrl(link.dataset.externalUrl || link.href);
+});
btnAutoStartClose?.addEventListener('click', () => resolveModalChoice(null));
async function startAutoRunFromCurrentSettings() {
@@ -13094,6 +13177,30 @@ mail2925ModeButtons.forEach((button) => {
});
});
+tempEmailLookupModeButtons.forEach((button) => {
+ button.addEventListener('click', async () => {
+ const nextMode = normalizeCloudflareTempEmailLookupMode(button.dataset.tempEmailLookupMode);
+ const previousMode = getSelectedCloudflareTempEmailLookupMode();
+ if (nextMode === previousMode) {
+ return;
+ }
+
+ if (nextMode === CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL) {
+ const confirmed = await confirmCloudflareTempEmailRegistrationLookupIfNeeded();
+ if (!confirmed) {
+ setCloudflareTempEmailLookupMode(previousMode);
+ updateMailProviderUI();
+ return;
+ }
+ }
+
+ setCloudflareTempEmailLookupMode(nextMode);
+ updateMailProviderUI();
+ markSettingsDirty(true);
+ saveSettings({ silent: true }).catch(() => { });
+ });
+});
+
selectEmailGenerator.addEventListener('change', () => {
updateMailProviderUI();
clearRegistrationEmail({ silent: true }).catch(() => { });
@@ -14962,6 +15069,9 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
if (message.payload.cloudflareTempEmailCustomAuth !== undefined) {
inputTempEmailCustomAuth.value = message.payload.cloudflareTempEmailCustomAuth || '';
}
+ if (message.payload.cloudflareTempEmailLookupMode !== undefined) {
+ setCloudflareTempEmailLookupMode(message.payload.cloudflareTempEmailLookupMode);
+ }
if (message.payload.cloudflareTempEmailReceiveMailbox !== undefined) {
inputTempEmailReceiveMailbox.value = message.payload.cloudflareTempEmailReceiveMailbox || '';
}
@@ -14973,6 +15083,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
}
if (
message.payload.cloudflareTempEmailUseRandomSubdomain !== undefined
+ || message.payload.cloudflareTempEmailLookupMode !== undefined
|| message.payload.cloudflareTempEmailDomain !== undefined
|| message.payload.cloudflareTempEmailDomains !== undefined
) {
@@ -15562,6 +15673,7 @@ updateSaveButtonState();
updateConfigMenuControls();
setLocalCpaStep9Mode(DEFAULT_LOCAL_CPA_STEP9_MODE);
setMail2925Mode(DEFAULT_MAIL_2925_MODE);
+setCloudflareTempEmailLookupMode(DEFAULT_CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE);
initializeReleaseInfo().catch((err) => {
console.error('Failed to initialize release info:', err);
});
diff --git a/tests/background-cloudflare-temp-email-settings.test.js b/tests/background-cloudflare-temp-email-settings.test.js
index e84b6c1..e0be738 100644
--- a/tests/background-cloudflare-temp-email-settings.test.js
+++ b/tests/background-cloudflare-temp-email-settings.test.js
@@ -50,6 +50,7 @@ function extractFunction(name) {
test('cloudflare temp email settings normalize and expose the random-subdomain toggle', () => {
const bundle = [
+ extractFunction('normalizeCloudflareTempEmailLookupMode'),
extractFunction('normalizeCloudflareTempEmailReceiveMailbox'),
extractFunction('getCloudflareTempEmailConfig'),
extractFunction('normalizePersistentSettingValue'),
@@ -58,6 +59,9 @@ test('cloudflare temp email settings normalize and expose the random-subdomain t
const api = new Function(`
const DEFAULT_VERIFICATION_RESEND_COUNT = 4;
+const CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_RECEIVE_MAILBOX = 'receive-mailbox';
+const CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL = 'registration-email';
+const DEFAULT_CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE = CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_RECEIVE_MAILBOX;
const PERSISTED_SETTING_DEFAULTS = {
panelMode: 'cpa',
autoStepDelaySeconds: null,
@@ -67,6 +71,7 @@ const PERSISTED_SETTING_DEFAULTS = {
emailGenerator: 'duck',
autoDeleteUsedIcloudAlias: false,
accountRunHistoryTextEnabled: false,
+ cloudflareTempEmailLookupMode: 'receive-mailbox',
cloudflareTempEmailUseRandomSubdomain: false,
cloudflareTempEmailDomain: '',
cloudflareTempEmailDomains: [],
@@ -116,12 +121,16 @@ return {
`)();
assert.equal(api.normalizePersistentSettingValue('cloudflareTempEmailUseRandomSubdomain', 1), true);
+ assert.equal(api.normalizePersistentSettingValue('cloudflareTempEmailLookupMode', 'registration-email'), 'registration-email');
+ assert.equal(api.normalizePersistentSettingValue('cloudflareTempEmailLookupMode', 'bad'), 'receive-mailbox');
const payload = api.buildPersistentSettingsPayload({
+ cloudflareTempEmailLookupMode: 'registration-email',
cloudflareTempEmailUseRandomSubdomain: true,
cloudflareTempEmailDomain: 'mail.example.com',
cloudflareTempEmailDomains: ['mail.example.com', 'alt.example.com'],
});
+ assert.equal(payload.cloudflareTempEmailLookupMode, 'registration-email');
assert.equal(payload.cloudflareTempEmailUseRandomSubdomain, true);
assert.equal(payload.cloudflareTempEmailDomain, 'mail.example.com');
assert.deepEqual(payload.cloudflareTempEmailDomains, ['mail.example.com', 'alt.example.com']);
@@ -130,6 +139,7 @@ return {
cloudflareTempEmailBaseUrl: 'https://temp.example.com',
cloudflareTempEmailAdminAuth: 'admin-secret',
cloudflareTempEmailCustomAuth: 'custom-secret',
+ cloudflareTempEmailLookupMode: 'registration-email',
cloudflareTempEmailReceiveMailbox: 'Forward@Example.com',
cloudflareTempEmailUseRandomSubdomain: true,
cloudflareTempEmailDomain: 'mail.example.com',
@@ -139,6 +149,7 @@ return {
baseUrl: 'https://temp.example.com',
adminAuth: 'admin-secret',
customAuth: 'custom-secret',
+ lookupMode: 'registration-email',
receiveMailbox: 'forward@example.com',
useRandomSubdomain: true,
domain: 'mail.example.com',
diff --git a/tests/cloudflare-temp-email-provider.test.js b/tests/cloudflare-temp-email-provider.test.js
index 57d1baf..abdd48d 100644
--- a/tests/cloudflare-temp-email-provider.test.js
+++ b/tests/cloudflare-temp-email-provider.test.js
@@ -68,6 +68,7 @@ function createProviderApi(options = {}) {
const bundle = [
extractFunction('isStopError'),
extractFunction('throwIfStopped'),
+ extractFunction('normalizeCloudflareTempEmailLookupMode'),
extractFunction('normalizeCloudflareTempEmailReceiveMailbox'),
extractFunction('resolveCloudflareTempEmailPollTargetEmail'),
extractFunction('summarizeCloudflareTempEmailMessagesForLog'),
@@ -78,6 +79,9 @@ function createProviderApi(options = {}) {
let stopRequested = false;
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
const CLOUDFLARE_TEMP_EMAIL_DEFAULT_PAGE_SIZE = 20;
+const CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_RECEIVE_MAILBOX = 'receive-mailbox';
+const CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL = 'registration-email';
+const DEFAULT_CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE = CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_RECEIVE_MAILBOX;
const logs = [];
const listCalls = [];
const messages = options.messages;
@@ -89,13 +93,29 @@ async function addLog(message, level) {
}
async function sleepWithStop() {}
function ensureCloudflareTempEmailConfig() {
- return { receiveMailbox: options.receiveMailbox };
+ return {
+ receiveMailbox: options.receiveMailbox,
+ lookupMode: options.lookupMode || 'receive-mailbox',
+ };
}
async function listCloudflareTempEmailMessages(_state, config) {
- listCalls.push(config.address);
+ listCalls.push({
+ address: config.address,
+ lookupMode: config.lookupMode,
+ originalRecipient: config.originalRecipient,
+ });
+ if (config.lookupMode === 'registration-email' && config.originalRecipient) {
+ const hasOriginalRecipient = messages.some((message) => normalizeCloudflareTempEmailReceiveMailbox(message.originalRecipient));
+ return {
+ config: {},
+ messages: messages.filter((message) => normalizeCloudflareTempEmailReceiveMailbox(message.originalRecipient) === normalizeCloudflareTempEmailReceiveMailbox(config.originalRecipient)),
+ missingOriginalRecipient: messages.length > 0 && !hasOriginalRecipient,
+ };
+ }
return {
config: {},
messages,
+ missingOriginalRecipient: false,
};
}
function pickVerificationMessageWithTimeFallback(currentMessages) {
@@ -145,7 +165,7 @@ test('pollCloudflareTempEmailVerificationCode returns code even if delete fails'
assert.equal(result.code, '123456');
const state = api.snapshot();
assert.equal(state.logs.some((entry) => entry.message.includes('删除 Cloudflare Temp Email 邮件失败')), true);
- assert.deepEqual(state.listCalls, ['user@example.com']);
+ assert.deepEqual(state.listCalls.map((call) => call.address), ['user@example.com']);
});
test('pollCloudflareTempEmailVerificationCode requires target email or receive mailbox', async () => {
@@ -182,7 +202,7 @@ test('pollCloudflareTempEmailVerificationCode prefers configured receive mailbox
});
assert.equal(result.code, '654321');
- assert.deepEqual(api.snapshot().listCalls, ['forward-box@email.20021108.xyz']);
+ assert.deepEqual(api.snapshot().listCalls.map((call) => call.address), ['forward-box@email.20021108.xyz']);
});
test('pollCloudflareTempEmailVerificationCode ignores stale receive mailbox when the field should be hidden', async () => {
@@ -210,5 +230,51 @@ test('pollCloudflareTempEmailVerificationCode ignores stale receive mailbox when
});
assert.equal(result.code, '246810');
- assert.deepEqual(api.snapshot().listCalls, ['generated@email.20021108.xyz']);
+ assert.deepEqual(api.snapshot().listCalls.map((call) => call.address), ['generated@email.20021108.xyz']);
+});
+
+test('pollCloudflareTempEmailVerificationCode filters by original recipient in registration lookup mode', async () => {
+ const api = createProviderApi({
+ receiveMailbox: 'forward-box@email.20021108.xyz',
+ lookupMode: 'registration-email',
+ messages: [
+ {
+ id: 'mail-4',
+ address: 'forward-box@email.20021108.xyz',
+ originalRecipient: 'other@duck.com',
+ receivedDateTime: '2026-04-13T12:20:00.000Z',
+ subject: 'Other verification code',
+ from: { emailAddress: { address: 'noreply@tm.openai.com' } },
+ bodyPreview: 'Your verification code is 111111.',
+ },
+ {
+ id: 'mail-5',
+ address: 'forward-box@email.20021108.xyz',
+ originalRecipient: 'duck-forwarded@duck.com',
+ receivedDateTime: '2026-04-13T12:21:00.000Z',
+ subject: 'Login verification code',
+ from: { emailAddress: { address: 'noreply@tm.openai.com' } },
+ bodyPreview: 'Your verification code is 222222.',
+ },
+ ],
+ });
+
+ const result = await api.pollCloudflareTempEmailVerificationCode(4, {
+ email: 'duck-forwarded@duck.com',
+ mailProvider: 'cloudflare-temp-email',
+ emailGenerator: 'duck',
+ cloudflareTempEmailLookupMode: 'registration-email',
+ cloudflareTempEmailReceiveMailbox: 'forward-box@email.20021108.xyz',
+ }, {
+ targetEmail: 'duck-forwarded@duck.com',
+ maxAttempts: 1,
+ intervalMs: 1,
+ });
+
+ assert.equal(result.code, '222222');
+ assert.deepEqual(api.snapshot().listCalls, [{
+ address: '',
+ lookupMode: 'registration-email',
+ originalRecipient: 'duck-forwarded@duck.com',
+ }]);
});
diff --git a/tests/cloudflare-temp-email-utils.test.js b/tests/cloudflare-temp-email-utils.test.js
index cbf08a8..1edaf83 100644
--- a/tests/cloudflare-temp-email-utils.test.js
+++ b/tests/cloudflare-temp-email-utils.test.js
@@ -55,6 +55,7 @@ test('normalizeCloudflareTempEmailMailApiMessages extracts sender, subject, code
{
id: 'mail-1',
address: 'user@example.com',
+ original_recipient: 'Forwarded.User@Duck.com',
created_at: '2026-04-13T09:15:00.000Z',
raw: [
'From: OpenAI
',
@@ -70,6 +71,7 @@ test('normalizeCloudflareTempEmailMailApiMessages extracts sender, subject, code
assert.equal(messages.length, 1);
assert.equal(messages[0].id, 'mail-1');
assert.equal(messages[0].address, 'user@example.com');
+ assert.equal(messages[0].originalRecipient, 'forwarded.user@duck.com');
assert.equal(messages[0].subject, 'OpenAI verification code');
assert.equal(messages[0].from.emailAddress.address, 'OpenAI ');
assert.match(messages[0].bodyPreview, /654321/);
diff --git a/tests/sidepanel-cloudflare-temp-email-random-subdomain.test.js b/tests/sidepanel-cloudflare-temp-email-random-subdomain.test.js
index 303a298..eb723f6 100644
--- a/tests/sidepanel-cloudflare-temp-email-random-subdomain.test.js
+++ b/tests/sidepanel-cloudflare-temp-email-random-subdomain.test.js
@@ -63,6 +63,10 @@ test('sidepanel html places cloudflare temp email controls in a standalone secti
assert.match(html, /id="cloudflare-temp-email-section"/);
assert.match(html, /id="btn-cloudflare-temp-email-usage-guide"/);
assert.match(html, /id="btn-cloudflare-temp-email-github"/);
+ assert.match(html, /btn-cloudflare-temp-email-github"[^>]*>部署);
+ assert.match(html, /id="row-temp-email-lookup-mode"/);
+ assert.match(html, /data-temp-email-lookup-mode="receive-mailbox"/);
+ assert.match(html, /data-temp-email-lookup-mode="registration-email"/);
assert.match(html, /id="row-temp-email-random-subdomain-toggle"/);
assert.match(html, /id="input-temp-email-use-random-subdomain"/);
assert.match(html, /id="btn-temp-email-domain-mode"[^>]*>更新);
@@ -111,12 +115,12 @@ return {
assert.deepEqual(api.openedUrls, []);
});
-test('openCloudflareTempEmailRepositoryPage opens the upstream repository', () => {
+test('openCloudflareTempEmailRepositoryPage opens the extension author repository', () => {
const bundle = extractFunction('openCloudflareTempEmailRepositoryPage');
const api = new Function(`
const calls = [];
-const CLOUDFLARE_TEMP_EMAIL_REPOSITORY_URL = 'https://github.com/dreamhunter2333/cloudflare_temp_email';
+const CLOUDFLARE_TEMP_EMAIL_REPOSITORY_URL = 'https://github.com/QLHazyCoder/cloudflare_temp_email';
function openExternalUrl(url) { calls.push(url); }
${bundle}
return {
@@ -126,7 +130,7 @@ return {
`)();
api.openCloudflareTempEmailRepositoryPage();
- assert.deepEqual(api.calls, ['https://github.com/dreamhunter2333/cloudflare_temp_email']);
+ assert.deepEqual(api.calls, ['https://github.com/QLHazyCoder/cloudflare_temp_email']);
});
test('applyCloudflareTempEmailSettingsState restores the random subdomain toggle and temp domain list', () => {
@@ -141,9 +145,11 @@ const inputTempEmailUseRandomSubdomain = { checked: false };
const calls = {
domainOptions: [],
domainEditMode: [],
+ lookupModes: [],
};
function renderCloudflareTempEmailDomainOptions(value) { calls.domainOptions.push(value); }
function setCloudflareTempEmailDomainEditMode(editing, options) { calls.domainEditMode.push({ editing, options }); }
+function setCloudflareTempEmailLookupMode(value) { calls.lookupModes.push(value); }
${bundle}
return {
applyCloudflareTempEmailSettingsState,
@@ -160,6 +166,7 @@ return {
cloudflareTempEmailBaseUrl: 'https://temp.example.com',
cloudflareTempEmailAdminAuth: 'admin-secret',
cloudflareTempEmailCustomAuth: 'custom-secret',
+ cloudflareTempEmailLookupMode: 'registration-email',
cloudflareTempEmailReceiveMailbox: 'relay@example.com',
cloudflareTempEmailUseRandomSubdomain: true,
cloudflareTempEmailDomain: 'mail.example.com',
@@ -170,6 +177,7 @@ return {
assert.equal(api.inputTempEmailCustomAuth.value, 'custom-secret');
assert.equal(api.inputTempEmailReceiveMailbox.value, 'relay@example.com');
assert.equal(api.inputTempEmailUseRandomSubdomain.checked, true);
+ assert.deepEqual(api.calls.lookupModes, ['registration-email']);
assert.deepEqual(api.calls.domainOptions, ['mail.example.com']);
assert.deepEqual(api.calls.domainEditMode, [{ editing: false, options: { clearInput: true } }]);
});
@@ -394,6 +402,7 @@ let cloudflareTempEmailDomainEditMode = false;
const ICLOUD_PROVIDER = 'icloud';
const GMAIL_PROVIDER = 'gmail';
const LUCKMAIL_PROVIDER = 'luckmail-api';
+const CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE_REGISTRATION_EMAIL = 'registration-email';
const rowMail2925Mode = ${JSON.stringify(createRow('none'))};
const rowMail2925PoolSettings = ${JSON.stringify(createRow('none'))};
const rowEmailPrefix = ${JSON.stringify(createRow('none'))};
@@ -404,6 +413,7 @@ const rowCfDomain = ${JSON.stringify(createRow('none'))};
const rowTempEmailBaseUrl = ${JSON.stringify(createRow('none'))};
const rowTempEmailAdminAuth = ${JSON.stringify(createRow('none'))};
const rowTempEmailCustomAuth = ${JSON.stringify(createRow('none'))};
+const rowTempEmailLookupMode = ${JSON.stringify(createRow('none'))};
const rowTempEmailReceiveMailbox = ${JSON.stringify(createRow('none'))};
const rowTempEmailRandomSubdomainToggle = ${JSON.stringify(createRow('none'))};
const rowTempEmailDomain = ${JSON.stringify(createRow('none'))};
@@ -435,6 +445,8 @@ function isCustomMailProvider() { return false; }
function isIcloudMailProvider() { return false; }
function usesGeneratedAliasMailProvider() { return false; }
function getSelectedMail2925Mode() { return 'provide'; }
+let selectedCloudflareTempEmailLookupMode = 'receive-mailbox';
+function getSelectedCloudflareTempEmailLookupMode() { return selectedCloudflareTempEmailLookupMode; }
function getManagedAliasProviderUiCopy() { return null; }
function getCurrentRegistrationEmailUiCopy() {
return {
@@ -462,9 +474,16 @@ ${bundle}
return {
updateMailProviderUI,
cloudflareTempEmailSection,
+ rowTempEmailLookupMode,
+ rowTempEmailReceiveMailbox,
rowTempEmailRandomSubdomainToggle,
rowTempEmailDomain,
inputTempEmailUseRandomSubdomain,
+ selectMailProvider,
+ selectEmailGenerator,
+ setLookupMode(value) {
+ selectedCloudflareTempEmailLookupMode = value;
+ },
autoHintText,
calls,
};
@@ -475,6 +494,20 @@ return {
assert.equal(api.rowTempEmailRandomSubdomainToggle.style.display, '');
assert.equal(api.rowTempEmailDomain.style.display, '');
+ api.selectMailProvider.value = 'cloudflare-temp-email';
+ api.selectEmailGenerator.value = 'duck';
+ api.setLookupMode('receive-mailbox');
+ api.updateMailProviderUI();
+ assert.equal(api.rowTempEmailLookupMode.style.display, '');
+ assert.equal(api.rowTempEmailReceiveMailbox.style.display, '');
+
+ api.setLookupMode('registration-email');
+ api.updateMailProviderUI();
+ assert.equal(api.rowTempEmailLookupMode.style.display, '');
+ assert.equal(api.rowTempEmailReceiveMailbox.style.display, 'none');
+
+ api.selectMailProvider.value = '163';
+ api.selectEmailGenerator.value = 'cloudflare-temp-email';
api.inputTempEmailUseRandomSubdomain.checked = true;
api.updateMailProviderUI();
assert.equal(api.cloudflareTempEmailSection.style.display, '');
diff --git a/tests/step-definitions-module.test.js b/tests/step-definitions-module.test.js
index 67445a8..835161d 100644
--- a/tests/step-definitions-module.test.js
+++ b/tests/step-definitions-module.test.js
@@ -79,6 +79,7 @@ test('step definitions module exposes ordered normal and Plus step metadata', ()
'oauth-login',
'fetch-login-code',
'bind-email',
+ 'fetch-bind-email-code',
'relogin-bound-email',
'fetch-bound-email-login-code',
'post-bound-email-phone-verification',
@@ -87,7 +88,7 @@ test('step definitions module exposes ordered normal and Plus step metadata', ()
]
);
assert.equal(phoneReloginSteps.find((step) => step.key === 'relogin-bound-email')?.title, '绑定邮箱后刷新 OAuth 并登录(邮箱)');
- assert.equal(phoneReloginSteps.some((step) => step.key === 'fetch-bind-email-code'), false);
+ assert.equal(phoneReloginSteps.find((step) => step.key === 'fetch-bind-email-code')?.title, '获取绑定邮箱验证码');
assert.deepStrictEqual(
plusSteps.map((step) => step.key),
@@ -134,11 +135,12 @@ test('step definitions module exposes ordered normal and Plus step metadata', ()
]
);
assert.deepStrictEqual(
- plusPhoneReloginSteps.map((step) => step.key).slice(-8),
+ plusPhoneReloginSteps.map((step) => step.key).slice(-9),
[
'oauth-login',
'fetch-login-code',
'bind-email',
+ 'fetch-bind-email-code',
'relogin-bound-email',
'fetch-bound-email-login-code',
'post-bound-email-phone-verification',
@@ -153,8 +155,8 @@ test('step definitions module exposes ordered normal and Plus step metadata', ()
assert.equal(api.getLastStepId({ plusModeEnabled: true }), 14);
assert.deepStrictEqual(api.getStepIds({ plusModeEnabled: true, signupMethod: 'phone' }), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
assert.equal(api.getLastStepId({ plusModeEnabled: true, signupMethod: 'phone' }), 15);
- assert.deepStrictEqual(api.getStepIds({ plusModeEnabled: true, signupMethod: 'phone', phoneSignupReloginAfterBindEmailEnabled: true }), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]);
- assert.equal(api.getLastStepId({ plusModeEnabled: true, signupMethod: 'phone', phoneSignupReloginAfterBindEmailEnabled: true }), 17);
+ assert.deepStrictEqual(api.getStepIds({ plusModeEnabled: true, signupMethod: 'phone', phoneSignupReloginAfterBindEmailEnabled: true }), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]);
+ assert.equal(api.getLastStepId({ plusModeEnabled: true, signupMethod: 'phone', phoneSignupReloginAfterBindEmailEnabled: true }), 18);
assert.equal(api.hasFlow('openai'), true);
assert.equal(api.hasFlow('site-a'), false);
assert.deepStrictEqual(api.getRegisteredFlowIds(), ['openai']);
diff --git a/tests/step8-state-timeout-retry.test.js b/tests/step8-state-timeout-retry.test.js
index 7cef424..2d23789 100644
--- a/tests/step8-state-timeout-retry.test.js
+++ b/tests/step8-state-timeout-retry.test.js
@@ -45,6 +45,12 @@ assert.strictEqual(
'普通内容脚本超时也应沿用可重试分支'
);
+assert.strictEqual(
+ api.isRetryableContentScriptTransportError(new Error('认证页 内容脚本 1 秒内未响应,请刷新页面后重试。')),
+ true,
+ '中文内容脚本超时也应沿用可重试分支'
+);
+
assert.strictEqual(
api.isRetryableContentScriptTransportError(new Error('按钮不存在')),
false,
diff --git a/tests/verification-flow-polling.test.js b/tests/verification-flow-polling.test.js
index 19ebcec..2a9eb11 100644
--- a/tests/verification-flow-polling.test.js
+++ b/tests/verification-flow-polling.test.js
@@ -1682,6 +1682,57 @@ test('verification flow does not replay step 8 code submit after transient auth-
assert.deepStrictEqual(resilientMessages, ['GET_LOGIN_AUTH_STATE']);
});
+test('verification flow keeps step 8 code submit response timeout above local floor when flow budget is nearly exhausted', async () => {
+ const directCalls = [];
+
+ const helpers = api.createVerificationFlowHelpers({
+ addLog: async () => {},
+ chrome: {
+ tabs: {
+ update: async () => {},
+ },
+ },
+ CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
+ completeNodeFromBackground: async () => {},
+ confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
+ getHotmailVerificationPollConfig: () => ({}),
+ getHotmailVerificationRequestTimestamp: () => 0,
+ getState: async () => ({}),
+ getTabId: async () => 1,
+ HOTMAIL_PROVIDER: 'hotmail-api',
+ isStopError: () => false,
+ LUCKMAIL_PROVIDER: 'luckmail-api',
+ MAIL_2925_VERIFICATION_INTERVAL_MS: 15000,
+ MAIL_2925_VERIFICATION_MAX_ATTEMPTS: 15,
+ pollCloudflareTempEmailVerificationCode: async () => ({}),
+ pollHotmailVerificationCode: async () => ({}),
+ pollLuckmailVerificationCode: async () => ({}),
+ sendToContentScript: async (_source, message, options) => {
+ directCalls.push({ message, options });
+ return { success: true };
+ },
+ sendToContentScriptResilient: async () => {
+ throw new Error('step 8 code submit should use the direct channel once');
+ },
+ sendToMailContentScriptResilient: async () => ({}),
+ setState: async () => {},
+ setStepStatus: async () => {},
+ sleepWithStop: async () => {},
+ throwIfStopped: () => {},
+ VERIFICATION_POLL_MAX_ROUNDS: 5,
+ });
+
+ const result = await helpers.submitVerificationCode(8, '478910', {
+ completionStep: 11,
+ getRemainingTimeMs: async () => 1000,
+ });
+
+ assert.deepStrictEqual(result, { success: true });
+ assert.equal(directCalls.length, 1);
+ assert.equal(directCalls[0].message.type, 'FILL_CODE');
+ assert.equal(directCalls[0].options.responseTimeoutMs, 15000);
+});
+
test('verification flow requests a new code immediately after Cloudflare Temp Email code is rejected', async () => {
const events = [];
const pollPayloads = [];