From 3763da7a14ca7fa7d0d34dd8f0a05fed3a957353 Mon Sep 17 00:00:00 2001 From: imxiaozhan Date: Sun, 10 May 2026 04:57:09 -0400 Subject: [PATCH] fix: detect contact-verification 500 without content scripts --- background.js | 15 +- background/phone-verification-flow.js | 13 +- tests/background-auth-tab-snapshot.test.js | 85 +++++++++++ tests/phone-verification-flow.test.js | 170 +++++++++++++++++++++ 4 files changed, 280 insertions(+), 3 deletions(-) create mode 100644 tests/background-auth-tab-snapshot.test.js diff --git a/background.js b/background.js index df04191..fd0e726 100644 --- a/background.js +++ b/background.js @@ -12209,6 +12209,17 @@ async function readAuthTabSnapshot(tabId) { if (!Number.isInteger(tabId)) { return null; } + let tabSnapshot = null; + try { + const tab = await chrome.tabs.get(tabId); + tabSnapshot = { + url: String(tab?.url || ''), + title: String(tab?.title || ''), + text: '', + }; + } catch { + tabSnapshot = null; + } try { const executionResults = await chrome.scripting.executeScript({ target: { tabId }, @@ -12219,9 +12230,9 @@ async function readAuthTabSnapshot(tabId) { text: String(document.body?.innerText || document.documentElement?.innerText || '').trim(), }), }); - return executionResults?.[0]?.result || null; + return executionResults?.[0]?.result || tabSnapshot; } catch { - return null; + return tabSnapshot; } } diff --git a/background/phone-verification-flow.js b/background/phone-verification-flow.js index 7cd9694..e81bf75 100644 --- a/background/phone-verification-flow.js +++ b/background/phone-verification-flow.js @@ -1413,9 +1413,19 @@ if (!/\/contact-verification(?:[/?#]|$)/i.test(rawUrl)) { return ''; } - const combined = [ + const bodyText = [ snapshot?.text, snapshot?.bodyText, + ] + .filter(Boolean) + .join(' ') + .replace(/\s+/g, ' ') + .trim(); + if (!bodyText) { + return 'OpenAI contact-verification page returned HTTP ERROR 500 after resend.'; + } + const combined = [ + bodyText, snapshot?.title, ] .filter(Boolean) @@ -5460,6 +5470,7 @@ if (isStopRequestedError(error) || isStaleSignupPhoneEmailVerificationError(error)) { throw error; } + await throwPhoneResendServerErrorIfAuthTabShowsIt(tabId); await addLog( `步骤 4:检查注册手机号页面状态(${phaseLabel})失败,将继续等待短信。${error.message}`, 'warn', diff --git a/tests/background-auth-tab-snapshot.test.js b/tests/background-auth-tab-snapshot.test.js new file mode 100644 index 0000000..e1884eb --- /dev/null +++ b/tests/background-auth-tab-snapshot.test.js @@ -0,0 +1,85 @@ +const test = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); + +const source = fs.readFileSync('background.js', 'utf8'); + +function extractFunction(name) { + const markers = [`async function ${name}(`, `function ${name}(`]; + const start = markers + .map((marker) => source.indexOf(marker)) + .find((index) => index >= 0); + if (start < 0) { + throw new Error(`missing function ${name}`); + } + + let parenDepth = 0; + let signatureEnded = false; + let braceStart = -1; + for (let i = start; i < source.length; i += 1) { + const ch = source[i]; + if (ch === '(') { + parenDepth += 1; + } else if (ch === ')') { + parenDepth -= 1; + if (parenDepth === 0) { + signatureEnded = true; + } + } else if (ch === '{' && signatureEnded) { + braceStart = i; + break; + } + } + + if (braceStart < 0) { + throw new Error(`missing body for function ${name}`); + } + + let depth = 0; + let end = braceStart; + for (; end < source.length; end += 1) { + const ch = source[end]; + if (ch === '{') depth += 1; + if (ch === '}') { + depth -= 1; + if (depth === 0) { + end += 1; + break; + } + } + } + + return source.slice(start, end); +} + +function createApi(chrome) { + return new Function('chrome', ` +${extractFunction('readAuthTabSnapshot')} +return { readAuthTabSnapshot }; +`)(chrome); +} + +test('readAuthTabSnapshot falls back to tab URL when script execution fails on auth error pages', async () => { + const chrome = { + scripting: { + executeScript: async () => { + throw new Error('Cannot access contents of url "chrome-error://chromewebdata/".'); + }, + }, + tabs: { + get: async () => ({ + id: 1, + url: 'https://auth.openai.com/contact-verification', + title: 'auth.openai.com', + }), + }, + }; + + const api = createApi(chrome); + + assert.deepStrictEqual(await api.readAuthTabSnapshot(1), { + url: 'https://auth.openai.com/contact-verification', + title: 'auth.openai.com', + text: '', + }); +}); diff --git a/tests/phone-verification-flow.test.js b/tests/phone-verification-flow.test.js index 705ae17..e06681c 100644 --- a/tests/phone-verification-flow.test.js +++ b/tests/phone-verification-flow.test.js @@ -5891,6 +5891,7 @@ test('signup phone verification cancels activation when resend lands on contact- test('signup phone verification cancels activation when resend lands on contact-verification 500 page but content script drops', async () => { const requests = []; const tabSnapshots = []; + let resendAttempted = false; let currentState = { heroSmsApiKey: 'demo-key', heroSmsCountryId: 52, @@ -5927,6 +5928,13 @@ test('signup phone verification cancels activation when resend lands on contact- getState: async () => ({ ...currentState }), readAuthTabSnapshot: async () => { tabSnapshots.push('read'); + if (!resendAttempted) { + return { + url: 'https://auth.openai.com/phone-verification', + title: 'Verify your phone', + text: 'Enter the code sent to your phone.', + }; + } return { url: 'https://auth.openai.com/contact-verification', title: 'auth.openai.com', @@ -5934,7 +5942,14 @@ test('signup phone verification cancels activation when resend lands on contact- }; }, sendToContentScriptResilient: async (_source, message) => { + if (message.type === 'STEP8_GET_STATE') { + return { + phoneVerificationPage: true, + url: 'https://auth.openai.com/phone-verification', + }; + } if (message.type === 'RESEND_VERIFICATION_CODE') { + resendAttempted = true; throw new Error('Could not establish connection. Receiving end does not exist.'); } throw new Error(`Unexpected content-script message: ${message.type}`); @@ -5959,6 +5974,161 @@ test('signup phone verification cancels activation when resend lands on contact- assert.equal(requests.filter((request) => request.searchParams.get('action') === 'getStatus').length, 1); }); +test('signup phone verification treats contact-verification URL-only snapshot as resend server error', async () => { + let currentState = { + heroSmsApiKey: 'demo-key', + heroSmsCountryId: 52, + heroSmsCountryLabel: 'Thailand', + verificationResendCount: 0, + phoneCodeWaitSeconds: 60, + phoneCodeTimeoutWindows: 2, + phoneCodePollIntervalSeconds: 1, + phoneCodePollMaxRounds: 1, + signupPhoneActivation: { + activationId: '930002', + phoneNumber: '66953330004', + provider: 'hero-sms', + countryId: 52, + countryLabel: 'Thailand', + }, + }; + + const helpers = api.createPhoneVerificationHelpers({ + addLog: async () => {}, + fetchImpl: async (url) => { + const parsedUrl = new URL(url); + const action = parsedUrl.searchParams.get('action'); + const id = parsedUrl.searchParams.get('id'); + if (action === 'getStatus') { + return { ok: true, text: async () => 'STATUS_WAIT_CODE' }; + } + if (action === 'setStatus') { + return { ok: true, text: async () => `STATUS_UPDATED:${id}` }; + } + throw new Error(`Unexpected HeroSMS action: ${action}`); + }, + getState: async () => ({ ...currentState }), + readAuthTabSnapshot: async () => ({ + url: 'https://auth.openai.com/contact-verification', + title: 'auth.openai.com', + text: '', + }), + sendToContentScriptResilient: async (_source, message) => { + if (message.type === 'RESEND_VERIFICATION_CODE') { + throw new Error('Could not establish connection. Receiving end does not exist.'); + } + throw new Error(`Unexpected content-script message: ${message.type}`); + }, + setState: async (updates) => { + currentState = { ...currentState, ...updates }; + }, + sleepWithStop: async () => {}, + throwIfStopped: () => {}, + }); + + await assert.rejects( + () => helpers.completeSignupPhoneVerificationFlow(1, { state: currentState }), + (error) => { + assert.match(error.message, /^PHONE_RESEND_SERVER_ERROR::OpenAI contact-verification page returned HTTP ERROR 500 after resend\./); + return true; + } + ); + + assert.equal(currentState.signupPhoneActivation, null); +}); + +test('signup phone verification fails when contact-verification 500 appears after successful resend', async () => { + const messages = []; + let pageStateReads = 0; + let resendCalls = 0; + let currentState = { + heroSmsApiKey: 'demo-key', + heroSmsCountryId: 52, + heroSmsCountryLabel: 'Thailand', + verificationResendCount: 0, + phoneCodeWaitSeconds: 60, + phoneCodeTimeoutWindows: 2, + phoneCodePollIntervalSeconds: 1, + phoneCodePollMaxRounds: 1, + signupPhoneActivation: { + activationId: '930003', + phoneNumber: '66953330005', + provider: 'hero-sms', + countryId: 52, + countryLabel: 'Thailand', + }, + }; + + const helpers = api.createPhoneVerificationHelpers({ + addLog: async () => {}, + ensureStep8SignupPageReady: async () => {}, + fetchImpl: async (url) => { + const parsedUrl = new URL(url); + const action = parsedUrl.searchParams.get('action'); + const id = parsedUrl.searchParams.get('id'); + if (action === 'getStatus') { + return { ok: true, text: async () => 'STATUS_WAIT_CODE' }; + } + if (action === 'setStatus') { + return { ok: true, text: async () => `STATUS_UPDATED:${id}` }; + } + throw new Error(`Unexpected HeroSMS action: ${action}`); + }, + getState: async () => ({ ...currentState }), + readAuthTabSnapshot: async () => ({ + url: 'https://auth.openai.com/contact-verification', + title: "This page isn't working", + text: 'auth.openai.com is currently unable to handle this request. HTTP ERROR 500', + }), + sendToContentScriptResilient: async (_source, message) => { + messages.push(message.type); + if (message.type === 'STEP8_GET_STATE') { + pageStateReads += 1; + if (pageStateReads <= 2) { + return { + phoneVerificationPage: true, + url: 'https://auth.openai.com/phone-verification', + }; + } + throw new Error('Could not establish connection. Receiving end does not exist.'); + } + if (message.type === 'RESEND_VERIFICATION_CODE') { + resendCalls += 1; + return { + resent: true, + buttonText: 'Resend code', + url: 'https://auth.openai.com/phone-verification', + }; + } + throw new Error(`Unexpected content-script message: ${message.type}`); + }, + setState: async (updates) => { + currentState = { ...currentState, ...updates }; + }, + sleepWithStop: async () => {}, + throwIfStopped: () => {}, + }); + + await assert.rejects( + () => helpers.completeSignupPhoneVerificationFlow(1, { state: currentState }), + (error) => { + assert.match(error.message, /^PHONE_RESEND_SERVER_ERROR::/); + assert.match(error.message, /HTTP ERROR 500/); + assert.match(error.message, /This page isn't working/); + return true; + } + ); + + assert.equal(resendCalls, 1); + assert.deepStrictEqual(messages, [ + 'STEP8_GET_STATE', + 'STEP8_GET_STATE', + 'RESEND_VERIFICATION_CODE', + 'STEP8_GET_STATE', + ]); + assert.equal(currentState.signupPhoneActivation, null); +}); + test('phone verification helper skips page resend for 5sim timeouts and rotates number directly', async () => { const requests = []; const messages = [];