| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610 |
- const test = require('node:test');
- const assert = require('node:assert/strict');
- const fs = require('node:fs');
- const source = fs.readFileSync('background/verification-flow.js', 'utf8');
- const globalScope = {};
- const api = new Function('self', `${source}; return self.MultiPageBackgroundVerificationFlow;`)(globalScope);
- test('verification flow extends 2925 polling window', () => {
- const helpers = api.createVerificationFlowHelpers({
- A4SKY_PROVIDER: 'a4sky',
- addLog: async () => {},
- chrome: { tabs: { update: async () => {} } },
- CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
- completeStepFromBackground: 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,
- pollA4skyImapVerificationCode: async () => ({}),
- pollCloudflareTempEmailVerificationCode: async () => ({}),
- pollHotmailVerificationCode: async () => ({}),
- pollLuckmailVerificationCode: async () => ({}),
- sendToContentScript: async () => ({}),
- sendToMailContentScriptResilient: async () => ({}),
- setState: async () => {},
- setStepStatus: async () => {},
- sleepWithStop: async () => {},
- throwIfStopped: () => {},
- VERIFICATION_POLL_MAX_ROUNDS: 5,
- });
- const step4Payload = helpers.getVerificationPollPayload(4, { email: 'user@example.com', mailProvider: '2925' });
- const step8Payload = helpers.getVerificationPollPayload(8, { email: 'user@example.com', mailProvider: '2925' });
- assert.equal(step4Payload.maxAttempts, 15);
- assert.equal(step4Payload.intervalMs, 15000);
- assert.equal(step8Payload.maxAttempts, 15);
- assert.equal(step8Payload.intervalMs, 15000);
- });
- test('verification flow routes A4Sky provider to IMAP helper polling', async () => {
- let capturedPayload = null;
- const helpers = api.createVerificationFlowHelpers({
- A4SKY_PROVIDER: 'a4sky',
- addLog: async () => {},
- chrome: { tabs: { update: async () => {} } },
- CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
- completeStepFromBackground: async () => {},
- confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
- getHotmailVerificationPollConfig: () => ({}),
- getHotmailVerificationRequestTimestamp: () => 123,
- 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,
- pollA4skyImapVerificationCode: async (_step, _state, payload) => {
- capturedPayload = payload;
- return { code: '123456', emailTimestamp: 1 };
- },
- pollCloudflareTempEmailVerificationCode: async () => ({}),
- pollHotmailVerificationCode: async () => ({}),
- pollLuckmailVerificationCode: async () => ({}),
- sendToContentScript: async () => ({}),
- sendToMailContentScriptResilient: async () => ({}),
- setState: async () => {},
- setStepStatus: async () => {},
- sleepWithStop: async () => {},
- throwIfStopped: () => {},
- VERIFICATION_POLL_MAX_ROUNDS: 5,
- });
- const result = await helpers.pollFreshVerificationCode(4, {
- email: 'target@a4sky.com',
- mailProvider: 'a4sky',
- }, {
- provider: 'a4sky',
- label: 'A4Sky',
- }, {
- filterAfterTimestamp: 555,
- });
- assert.equal(result.code, '123456');
- assert.equal(capturedPayload.filterAfterTimestamp, 555);
- assert.equal(capturedPayload.targetEmail, 'target@a4sky.com');
- });
- test('verification flow runs beforeSubmit hook before filling the code', async () => {
- const events = [];
- const helpers = api.createVerificationFlowHelpers({
- addLog: async () => {},
- chrome: {
- tabs: {
- update: async () => {},
- },
- },
- CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
- completeStepFromBackground: async (_step, payload) => {
- events.push(['complete', payload.code]);
- },
- 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) => {
- if (message.type === 'FILL_CODE') {
- events.push(['submit', message.payload.code]);
- return {};
- }
- return {};
- },
- sendToMailContentScriptResilient: async () => ({
- code: '654321',
- emailTimestamp: 123,
- }),
- setState: async (payload) => {
- events.push(['state', payload.lastLoginCode || payload.lastSignupCode]);
- },
- setStepStatus: async () => {},
- sleepWithStop: async () => {},
- throwIfStopped: () => {},
- VERIFICATION_POLL_MAX_ROUNDS: 5,
- });
- await helpers.resolveVerificationStep(
- 7,
- { email: 'user@example.com', lastLoginCode: null },
- { provider: 'qq', label: 'QQ 邮箱' },
- {
- beforeSubmit: async (result) => {
- events.push(['beforeSubmit', result.code]);
- },
- }
- );
- assert.deepStrictEqual(events, [
- ['beforeSubmit', '654321'],
- ['state', '654321'],
- ['submit', '654321'],
- ['state', '654321'],
- ['complete', '654321'],
- ]);
- });
- test('verification flow excludes the previously submitted code on the next retry', async () => {
- const pollPayloads = [];
- let currentState = {
- email: 'user@example.com',
- signupVerificationRequestedAt: 0,
- lastSignupCode: null,
- };
- let submitCount = 0;
- const helpers = api.createVerificationFlowHelpers({
- addLog: async () => {},
- chrome: { tabs: { update: async () => {} } },
- CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
- completeStepFromBackground: async () => {},
- confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
- getHotmailVerificationPollConfig: () => ({}),
- getHotmailVerificationRequestTimestamp: () => 0,
- getState: async () => currentState,
- 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 (_step, _state, payload) => {
- pollPayloads.push(payload);
- return {
- code: Array.isArray(payload.excludeCodes) && payload.excludeCodes.includes('111111') ? '222222' : '111111',
- emailTimestamp: Date.now(),
- };
- },
- pollLuckmailVerificationCode: async () => ({}),
- sendToContentScript: async (_source, message) => {
- if (message.type === 'FILL_CODE') {
- submitCount += 1;
- if (submitCount === 1) {
- throw new Error('页面通信异常');
- }
- return {};
- }
- return {};
- },
- sendToMailContentScriptResilient: async () => ({}),
- setState: async (payload) => {
- currentState = { ...currentState, ...payload };
- },
- setStepStatus: async () => {},
- sleepWithStop: async () => {},
- throwIfStopped: () => {},
- VERIFICATION_POLL_MAX_ROUNDS: 5,
- });
- await assert.rejects(
- () => helpers.resolveVerificationStep(
- 4,
- currentState,
- { provider: 'hotmail-api', label: 'Hotmail' },
- {}
- ),
- /页面通信异常/
- );
- assert.equal(currentState.lastSignupCode, '111111');
- await helpers.resolveVerificationStep(
- 4,
- currentState,
- { provider: 'hotmail-api', label: 'Hotmail' },
- {}
- );
- assert.equal(currentState.lastSignupCode, '222222');
- assert.ok(
- pollPayloads.some((payload) => Array.isArray(payload.excludeCodes) && payload.excludeCodes.includes('111111')),
- 'next retry should exclude the previously submitted code'
- );
- });
- test('verification flow treats add-phone after login code submit as fatal instead of completing step 8', async () => {
- const events = [];
- const helpers = api.createVerificationFlowHelpers({
- addLog: async () => {},
- chrome: {
- tabs: {
- update: async () => {},
- },
- },
- CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
- completeStepFromBackground: async (_step, payload) => {
- events.push(['complete', payload.code]);
- },
- 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) => {
- if (message.type === 'FILL_CODE') {
- events.push(['submit', message.payload.code]);
- return {
- addPhonePage: true,
- url: 'https://auth.openai.com/add-phone',
- };
- }
- return {};
- },
- sendToMailContentScriptResilient: async () => ({
- code: '654321',
- emailTimestamp: 123,
- }),
- setState: async (payload) => {
- events.push(['state', payload.lastLoginCode || payload.lastSignupCode]);
- },
- setStepStatus: async () => {},
- sleepWithStop: async () => {},
- throwIfStopped: () => {},
- VERIFICATION_POLL_MAX_ROUNDS: 5,
- });
- await assert.rejects(
- () => helpers.resolveVerificationStep(
- 8,
- { email: 'user@example.com', lastLoginCode: null },
- { provider: 'qq', label: 'QQ 邮箱' },
- {}
- ),
- /验证码提交后页面进入手机号页面/
- );
- assert.deepStrictEqual(events, [
- ['state', '654321'],
- ['submit', '654321'],
- ]);
- });
- test('verification flow caps mail polling timeout to the remaining oauth budget', async () => {
- const mailPollCalls = [];
- const helpers = api.createVerificationFlowHelpers({
- addLog: async () => {},
- chrome: {
- tabs: {
- update: async () => {},
- },
- },
- CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
- completeStepFromBackground: 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) => {
- if (message.type === 'FILL_CODE') {
- return {};
- }
- return {};
- },
- sendToMailContentScriptResilient: async (_mail, message, options) => {
- mailPollCalls.push({
- payload: message.payload,
- options,
- });
- return { code: '654321', emailTimestamp: 123 };
- },
- setState: async () => {},
- setStepStatus: async () => {},
- sleepWithStop: async () => {},
- throwIfStopped: () => {},
- VERIFICATION_POLL_MAX_ROUNDS: 5,
- });
- await helpers.resolveVerificationStep(
- 8,
- {
- email: 'user@example.com',
- lastLoginCode: null,
- },
- { provider: 'qq', label: 'QQ 邮箱' },
- {
- getRemainingTimeMs: async () => 5000,
- resendIntervalMs: 0,
- }
- );
- assert.ok(mailPollCalls.length >= 1);
- assert.equal(mailPollCalls[0].options.timeoutMs, 5000);
- assert.equal(mailPollCalls[0].options.responseTimeoutMs, 5000);
- assert.equal(mailPollCalls[0].payload.maxAttempts, 2);
- });
- test('verification flow keeps Hotmail request timestamp filtering on the first poll', async () => {
- const pollPayloads = [];
- const helpers = api.createVerificationFlowHelpers({
- addLog: async () => {},
- chrome: { tabs: { update: async () => {} } },
- CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
- completeStepFromBackground: async () => {},
- confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
- getHotmailVerificationPollConfig: () => ({}),
- getHotmailVerificationRequestTimestamp: () => 87654,
- 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 (_step, _state, payload) => {
- pollPayloads.push(payload);
- return { code: '654321', emailTimestamp: 123 };
- },
- pollLuckmailVerificationCode: async () => ({}),
- sendToContentScript: async (_source, message) => {
- if (message.type === 'FILL_CODE') {
- return {};
- }
- return {};
- },
- sendToMailContentScriptResilient: async () => ({}),
- setState: async () => {},
- setStepStatus: async () => {},
- sleepWithStop: async () => {},
- throwIfStopped: () => {},
- VERIFICATION_POLL_MAX_ROUNDS: 5,
- });
- await helpers.resolveVerificationStep(
- 7,
- {
- email: 'user@example.com',
- loginVerificationRequestedAt: 100000,
- lastLoginCode: null,
- },
- { provider: 'hotmail-api', label: 'Hotmail' },
- {}
- );
- assert.equal(pollPayloads.length, 1);
- assert.equal(pollPayloads[0].filterAfterTimestamp, 87654);
- });
- test('verification flow keeps fixed filter timestamp after step 4 resend', async () => {
- const pollPayloads = [];
- let submitCount = 0;
- const helpers = api.createVerificationFlowHelpers({
- addLog: async () => {},
- chrome: { tabs: { update: async () => {} } },
- CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
- completeStepFromBackground: async () => {},
- confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
- getHotmailVerificationPollConfig: () => ({}),
- getHotmailVerificationRequestTimestamp: (_step, state) => Math.max(0, Number(state.signupVerificationRequestedAt || 0) - 15000),
- 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 (_step, _state, payload) => {
- pollPayloads.push(payload);
- return {
- code: pollPayloads.length === 1 ? '111111' : '222222',
- emailTimestamp: pollPayloads.length,
- };
- },
- pollLuckmailVerificationCode: async () => ({}),
- sendToContentScript: async (_source, message) => {
- if (message.type === 'FILL_CODE') {
- submitCount += 1;
- return submitCount === 1
- ? { invalidCode: true, errorText: '旧验证码' }
- : {};
- }
- if (message.type === 'RESEND_VERIFICATION_CODE') {
- return {};
- }
- return {};
- },
- sendToMailContentScriptResilient: async () => ({}),
- setState: async () => {},
- setStepStatus: async () => {},
- sleepWithStop: async () => {},
- throwIfStopped: () => {},
- VERIFICATION_POLL_MAX_ROUNDS: 5,
- });
- await helpers.resolveVerificationStep(
- 4,
- {
- email: 'user@example.com',
- signupVerificationRequestedAt: 100000,
- lastSignupCode: null,
- },
- { provider: 'hotmail-api', label: 'Hotmail' },
- {
- filterAfterTimestamp: 123456,
- }
- );
- assert.equal(pollPayloads.length, 2);
- assert.equal(pollPayloads[0].filterAfterTimestamp, 123456);
- assert.equal(pollPayloads[1].filterAfterTimestamp, 123456);
- });
- test('verification flow uses configured signup resend count for step 4', async () => {
- const resendSteps = [];
- let pollCalls = 0;
- const helpers = api.createVerificationFlowHelpers({
- addLog: async () => {},
- chrome: { tabs: { update: async () => {} } },
- CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
- completeStepFromBackground: 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) => {
- if (message.type === 'RESEND_VERIFICATION_CODE') {
- resendSteps.push(message.step);
- }
- return {};
- },
- sendToMailContentScriptResilient: async () => {
- pollCalls += 1;
- return pollCalls === 2
- ? { code: '654321', emailTimestamp: 123 }
- : {};
- },
- setState: async () => {},
- setStepStatus: async () => {},
- sleepWithStop: async () => {},
- throwIfStopped: () => {},
- VERIFICATION_POLL_MAX_ROUNDS: 5,
- });
- await helpers.resolveVerificationStep(
- 4,
- {
- email: 'user@example.com',
- verificationResendCount: 2,
- lastSignupCode: null,
- },
- { provider: 'qq', label: 'QQ 邮箱' },
- {
- requestFreshCodeFirst: true,
- resendIntervalMs: 0,
- }
- );
- assert.deepStrictEqual(resendSteps, [4, 4]);
- assert.equal(pollCalls, 2);
- });
- test('verification flow uses configured login resend count for step 8', async () => {
- const resendSteps = [];
- let pollCalls = 0;
- const helpers = api.createVerificationFlowHelpers({
- addLog: async () => {},
- chrome: { tabs: { update: async () => {} } },
- CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
- completeStepFromBackground: 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) => {
- if (message.type === 'RESEND_VERIFICATION_CODE') {
- resendSteps.push(message.step);
- }
- return {};
- },
- sendToMailContentScriptResilient: async () => {
- pollCalls += 1;
- return pollCalls === 3
- ? { code: '654321', emailTimestamp: 123 }
- : {};
- },
- setState: async () => {},
- setStepStatus: async () => {},
- sleepWithStop: async () => {},
- throwIfStopped: () => {},
- VERIFICATION_POLL_MAX_ROUNDS: 5,
- });
- await helpers.resolveVerificationStep(
- 8,
- {
- email: 'user@example.com',
- verificationResendCount: 2,
- lastLoginCode: null,
- },
- { provider: 'qq', label: 'QQ 邮箱' },
- {
- requestFreshCodeFirst: false,
- resendIntervalMs: 0,
- }
- );
- assert.deepStrictEqual(resendSteps, [8, 8]);
- assert.equal(pollCalls, 3);
- });
|