From 672c593271403c18622e138c72721bd9e8486e8f Mon Sep 17 00:00:00 2001 From: QLHazyCoder <2825305047@qq.com> Date: Sat, 25 Apr 2026 15:14:35 +0800 Subject: [PATCH] fix: close iCloud mail tabs after verification success --- background.js | 1 + background/navigation-utils.js | 3 + background/verification-flow.js | 28 +++++++- ...background-navigation-utils-module.test.js | 25 +++++++ tests/verification-flow-polling.test.js | 71 +++++++++++++++++++ 5 files changed, 127 insertions(+), 1 deletion(-) diff --git a/background.js b/background.js index 5846b83..1951a63 100644 --- a/background.js +++ b/background.js @@ -6492,6 +6492,7 @@ const signupFlowHelpers = self.MultiPageSignupFlowHelpers?.createSignupFlowHelpe const verificationFlowHelpers = self.MultiPageBackgroundVerificationFlow?.createVerificationFlowHelpers({ addLog, chrome, + closeConflictingTabsForSource, CLOUDFLARE_TEMP_EMAIL_PROVIDER, completeStepFromBackground, confirmCustomVerificationStepBypassRequest: (step) => chrome.runtime.sendMessage({ diff --git a/background/navigation-utils.js b/background/navigation-utils.js index edde364..3193a54 100644 --- a/background/navigation-utils.js +++ b/background/navigation-utils.js @@ -130,6 +130,9 @@ return is163MailHost(candidate.hostname); case 'gmail-mail': return candidate.hostname === 'mail.google.com'; + case 'icloud-mail': + return candidate.hostname === 'www.icloud.com' + || candidate.hostname === 'www.icloud.com.cn'; case 'inbucket-mail': return Boolean(reference) && candidate.origin === reference.origin diff --git a/background/verification-flow.js b/background/verification-flow.js index 7e33c45..dbc9594 100644 --- a/background/verification-flow.js +++ b/background/verification-flow.js @@ -5,6 +5,7 @@ const { addLog, chrome, + closeConflictingTabsForSource, CLOUDFLARE_TEMP_EMAIL_PROVIDER, completeStepFromBackground, confirmCustomVerificationStepBypassRequest, @@ -392,13 +393,38 @@ } } + async function closeIcloudMailboxTabAfterSuccess(step, mail) { + if (mail?.source !== 'icloud-mail') { + return; + } + + const tabId = typeof getTabId === 'function' + ? await getTabId(mail.source) + : null; + + if (Number.isInteger(tabId)) { + await chrome.tabs.remove(tabId).catch(() => {}); + await addLog(`步骤 ${step}:已关闭 iCloud 邮箱标签页,避免长期累积。`, 'info'); + return; + } + + if (typeof closeConflictingTabsForSource === 'function' && mail.url) { + await closeConflictingTabsForSource(mail.source, mail.url).catch(() => {}); + } + } + function triggerPostSuccessMailboxCleanup(step, mail) { - if (mail?.provider !== '2925') { + if (mail?.provider !== '2925' && mail?.source !== 'icloud-mail') { return; } Promise.resolve().then(async () => { try { + if (mail?.source === 'icloud-mail') { + await closeIcloudMailboxTabAfterSuccess(step, mail); + return; + } + await sendToMailContentScriptResilient( mail, { diff --git a/tests/background-navigation-utils-module.test.js b/tests/background-navigation-utils-module.test.js index a501ac4..5dbeb84 100644 --- a/tests/background-navigation-utils-module.test.js +++ b/tests/background-navigation-utils-module.test.js @@ -35,3 +35,28 @@ test('navigation utils support codex2api mode and url normalization', () => { assert.equal(utils.getPanelMode({ panelMode: 'codex2api' }), 'codex2api'); assert.equal(utils.getPanelModeLabel('codex2api'), 'Codex2API'); }); + +test('navigation utils recognize the iCloud mail tab family on both supported hosts', () => { + const source = fs.readFileSync('background/navigation-utils.js', 'utf8'); + const globalScope = {}; + + const api = new Function('self', `${source}; return self.MultiPageBackgroundNavigationUtils;`)(globalScope); + const utils = api.createNavigationUtils({ + DEFAULT_CODEX2API_URL: 'http://localhost:8080/admin/accounts', + DEFAULT_SUB2API_URL: 'https://sub.example.com/admin/accounts', + normalizeLocalCpaStep9Mode: (value) => value, + }); + + assert.equal( + utils.matchesSourceUrlFamily('icloud-mail', 'https://www.icloud.com/mail/', 'https://www.icloud.com/mail/'), + true + ); + assert.equal( + utils.matchesSourceUrlFamily('icloud-mail', 'https://www.icloud.com.cn/mail/', 'https://www.icloud.com.cn/mail/'), + true + ); + assert.equal( + utils.matchesSourceUrlFamily('icloud-mail', 'https://mail.google.com/mail/u/0/#inbox', 'https://www.icloud.com/mail/'), + false + ); +}); diff --git a/tests/verification-flow-polling.test.js b/tests/verification-flow-polling.test.js index 1d9fa1d..df4f6d8 100644 --- a/tests/verification-flow-polling.test.js +++ b/tests/verification-flow-polling.test.js @@ -280,6 +280,77 @@ test('verification flow skips 2925 mailbox preclear when using a fixed signup ma assert.deepStrictEqual(mailMessages, ['POLL_EMAIL', 'DELETE_ALL_EMAILS']); }); +test('verification flow closes the tracked iCloud mail tab after a successful verification submit', async () => { + const removedTabIds = []; + const logMessages = []; + + const helpers = api.createVerificationFlowHelpers({ + addLog: async (message) => { + logMessages.push(message); + }, + chrome: { + tabs: { + update: async () => {}, + remove: async (tabId) => { + removedTabIds.push(tabId); + }, + }, + }, + closeConflictingTabsForSource: async () => { + throw new Error('should not use family cleanup when tracked tab exists'); + }, + CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email', + completeStepFromBackground: async () => {}, + confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }), + getHotmailVerificationPollConfig: () => ({}), + getHotmailVerificationRequestTimestamp: () => 0, + getState: async () => ({}), + getTabId: async (source) => (source === 'icloud-mail' ? 91 : 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) => { + if (message.type === 'FILL_CODE') { + return {}; + } + return {}; + }, + sendToMailContentScriptResilient: async () => ({ + code: '654321', + emailTimestamp: 123, + }), + setState: async () => {}, + setStepStatus: async () => {}, + sleepWithStop: async () => {}, + throwIfStopped: () => {}, + VERIFICATION_POLL_MAX_ROUNDS: 5, + }); + + await helpers.resolveVerificationStep( + 4, + { + email: 'user@example.com', + lastSignupCode: null, + }, + { + source: 'icloud-mail', + url: 'https://www.icloud.com/mail/', + label: 'iCloud 邮箱', + }, + {} + ); + + await new Promise((resolve) => setTimeout(resolve, 0)); + + assert.deepStrictEqual(removedTabIds, [91]); + assert.ok(logMessages.some((message) => message.includes('已关闭 iCloud 邮箱标签页'))); +}); + test('verification flow completes step 8 and flags phone verification when add-phone appears after login code submit', async () => { const events = [];