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 @@
- +
+