2049 lines
65 KiB
JavaScript
2049 lines
65 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
|
|
const source = fs.readFileSync('background/phone-verification-flow.js', 'utf8');
|
|
const globalScope = {};
|
|
const api = new Function('self', `${source}; return self.MultiPageBackgroundPhoneVerification;`)(globalScope);
|
|
|
|
function buildHeroSmsPricesPayload({ country = '52', service = 'dr', cost = 0.08, count = 25370, physicalCount = 14528 } = {}) {
|
|
return JSON.stringify({
|
|
[country]: {
|
|
[service]: {
|
|
cost,
|
|
count,
|
|
physicalCount,
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
function buildHeroSmsStatusV2Payload({ smsCode = '', smsText = '', callCode = '' } = {}) {
|
|
return JSON.stringify({
|
|
verificationType: 2,
|
|
sms: {
|
|
dateTime: '2026-02-18T16:11:33+00:00',
|
|
code: smsCode,
|
|
text: smsText,
|
|
},
|
|
call: {
|
|
code: callCode,
|
|
},
|
|
});
|
|
}
|
|
|
|
test('phone verification helper requests HeroSMS numbers with fixed OpenAI and Thailand parameters', async () => {
|
|
const requests = [];
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload(),
|
|
};
|
|
}
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_NUMBER:123456:66959916439',
|
|
};
|
|
},
|
|
getState: async () => ({ heroSmsApiKey: 'demo-key' }),
|
|
sendToContentScriptResilient: async () => ({}),
|
|
setState: async () => {},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const activation = await helpers.requestPhoneActivation({ heroSmsApiKey: 'demo-key' });
|
|
|
|
assert.deepStrictEqual(activation, {
|
|
activationId: '123456',
|
|
phoneNumber: '66959916439',
|
|
provider: 'hero-sms',
|
|
serviceCode: 'dr',
|
|
countryId: 52,
|
|
successfulUses: 0,
|
|
maxUses: 3,
|
|
});
|
|
assert.equal(requests.length, 2);
|
|
assert.equal(requests[0].searchParams.get('action'), 'getPrices');
|
|
assert.equal(requests[0].searchParams.get('service'), 'dr');
|
|
assert.equal(requests[0].searchParams.get('country'), '52');
|
|
assert.equal(requests[0].searchParams.get('api_key'), 'demo-key');
|
|
assert.equal(requests[1].searchParams.get('action'), 'getNumber');
|
|
assert.equal(requests[1].searchParams.get('maxPrice'), '0.08');
|
|
assert.equal(requests[1].searchParams.get('fixedPrice'), 'true');
|
|
assert.equal(requests[1].searchParams.get('service'), 'dr');
|
|
assert.equal(requests[1].searchParams.get('country'), '52');
|
|
assert.equal(requests[1].searchParams.get('api_key'), 'demo-key');
|
|
});
|
|
|
|
test('phone verification helper retries HeroSMS getPrices until it receives a usable lowest price', async () => {
|
|
const requests = [];
|
|
let getPricesAttempt = 0;
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'getPrices') {
|
|
getPricesAttempt += 1;
|
|
return getPricesAttempt < 3
|
|
? {
|
|
ok: true,
|
|
text: async () => JSON.stringify({ unavailable: true }),
|
|
}
|
|
: {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload({ cost: 0.09 }),
|
|
};
|
|
}
|
|
if (action === 'getNumber') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_NUMBER:123456:66959916439',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getState: async () => ({ heroSmsApiKey: 'demo-key' }),
|
|
sendToContentScriptResilient: async () => ({}),
|
|
setState: async () => {},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
await helpers.requestPhoneActivation({ heroSmsApiKey: 'demo-key' });
|
|
|
|
assert.equal(requests.length, 4);
|
|
assert.equal(requests[0].searchParams.get('action'), 'getPrices');
|
|
assert.equal(requests[1].searchParams.get('action'), 'getPrices');
|
|
assert.equal(requests[2].searchParams.get('action'), 'getPrices');
|
|
assert.equal(requests[3].searchParams.get('action'), 'getNumber');
|
|
assert.equal(requests[3].searchParams.get('maxPrice'), '0.09');
|
|
assert.equal(requests[3].searchParams.get('fixedPrice'), 'true');
|
|
});
|
|
|
|
test('phone verification helper falls back to plain getNumber only after HeroSMS getPrices fails three times', async () => {
|
|
const requests = [];
|
|
let getPricesAttempt = 0;
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'getPrices') {
|
|
getPricesAttempt += 1;
|
|
return {
|
|
ok: true,
|
|
text: async () => JSON.stringify({ unavailable: getPricesAttempt }),
|
|
};
|
|
}
|
|
if (action === 'getNumber') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_NUMBER:123456:66959916439',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getState: async () => ({ heroSmsApiKey: 'demo-key' }),
|
|
sendToContentScriptResilient: async () => ({}),
|
|
setState: async () => {},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
await helpers.requestPhoneActivation({ heroSmsApiKey: 'demo-key' });
|
|
|
|
assert.equal(requests.length, 4);
|
|
assert.equal(requests[0].searchParams.get('action'), 'getPrices');
|
|
assert.equal(requests[1].searchParams.get('action'), 'getPrices');
|
|
assert.equal(requests[2].searchParams.get('action'), 'getPrices');
|
|
assert.equal(requests[2].searchParams.get('service'), 'dr');
|
|
assert.equal(requests[2].searchParams.get('country'), '52');
|
|
assert.equal(requests[2].searchParams.get('api_key'), 'demo-key');
|
|
assert.equal(requests[3].searchParams.get('action'), 'getNumber');
|
|
assert.equal(requests[3].searchParams.get('maxPrice'), null);
|
|
assert.equal(requests[3].searchParams.get('fixedPrice'), null);
|
|
});
|
|
|
|
test('phone verification helper retries with HeroSMS getNumberV2 when getNumber reports NO_NUMBERS', async () => {
|
|
const requests = [];
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload({ country: '16' }),
|
|
};
|
|
}
|
|
if (action === 'getNumber') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'NO_NUMBERS',
|
|
};
|
|
}
|
|
if (action === 'getNumberV2') {
|
|
return {
|
|
ok: true,
|
|
text: async () => JSON.stringify({
|
|
activationId: '654321',
|
|
phoneNumber: '447911123456',
|
|
}),
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getState: async () => ({ heroSmsApiKey: 'demo-key', heroSmsCountryId: 16 }),
|
|
sendToContentScriptResilient: async () => ({}),
|
|
setState: async () => {},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const activation = await helpers.requestPhoneActivation({
|
|
heroSmsApiKey: 'demo-key',
|
|
heroSmsCountryId: 16,
|
|
});
|
|
|
|
assert.deepStrictEqual(activation, {
|
|
activationId: '654321',
|
|
phoneNumber: '447911123456',
|
|
provider: 'hero-sms',
|
|
serviceCode: 'dr',
|
|
countryId: 16,
|
|
successfulUses: 0,
|
|
maxUses: 3,
|
|
statusAction: 'getStatusV2',
|
|
});
|
|
assert.equal(requests.length, 3);
|
|
assert.equal(requests[0].searchParams.get('action'), 'getPrices');
|
|
assert.equal(requests[0].searchParams.get('country'), '16');
|
|
assert.equal(requests[1].searchParams.get('action'), 'getNumber');
|
|
assert.equal(requests[1].searchParams.get('country'), '16');
|
|
assert.equal(requests[1].searchParams.get('maxPrice'), '0.08');
|
|
assert.equal(requests[1].searchParams.get('fixedPrice'), 'true');
|
|
assert.equal(requests[2].searchParams.get('action'), 'getNumberV2');
|
|
assert.equal(requests[2].searchParams.get('country'), '16');
|
|
assert.equal(requests[2].searchParams.get('maxPrice'), '0.08');
|
|
assert.equal(requests[2].searchParams.get('fixedPrice'), 'true');
|
|
});
|
|
|
|
test('phone verification helper applies ordered fallback countries when primary country has no numbers', async () => {
|
|
const requests = [];
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
const country = parsedUrl.searchParams.get('country');
|
|
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => JSON.stringify({
|
|
[country]: {
|
|
dr: {
|
|
cost: 0.08,
|
|
count: 100,
|
|
},
|
|
},
|
|
}),
|
|
};
|
|
}
|
|
|
|
if (action === 'getNumber' || action === 'getNumberV2') {
|
|
if (country === '52') {
|
|
return { ok: true, text: async () => 'NO_NUMBERS' };
|
|
}
|
|
if (country === '16' && action === 'getNumber') {
|
|
return { ok: true, text: async () => 'ACCESS_NUMBER:861234:447955001122' };
|
|
}
|
|
}
|
|
|
|
throw new Error(`Unexpected HeroSMS action: ${action} @ country ${country}`);
|
|
},
|
|
getState: async () => ({ heroSmsApiKey: 'demo-key', heroSmsCountryId: 52 }),
|
|
sendToContentScriptResilient: async () => ({}),
|
|
setState: async () => {},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const activation = await helpers.requestPhoneActivation({
|
|
heroSmsApiKey: 'demo-key',
|
|
heroSmsCountryId: 52,
|
|
heroSmsCountryLabel: 'Thailand',
|
|
heroSmsCountryFallback: [{ id: 16, label: 'United Kingdom' }],
|
|
});
|
|
|
|
assert.equal(activation.countryId, 16);
|
|
assert.equal(activation.phoneNumber, '447955001122');
|
|
const actionTrace = requests.map((requestUrl) => `${requestUrl.searchParams.get('action')}:${requestUrl.searchParams.get('country')}`);
|
|
assert.deepStrictEqual(actionTrace, [
|
|
'getPrices:52',
|
|
'getNumber:52',
|
|
'getNumberV2:52',
|
|
'getPrices:16',
|
|
'getNumber:16',
|
|
]);
|
|
});
|
|
|
|
test('phone verification helper honors price-priority acquisition mode across selected countries', async () => {
|
|
const requests = [];
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
const country = parsedUrl.searchParams.get('country');
|
|
|
|
if (action === 'getPrices') {
|
|
const cost = country === '52' ? 0.08 : 0.05;
|
|
return {
|
|
ok: true,
|
|
text: async () => JSON.stringify({
|
|
[country]: {
|
|
dr: {
|
|
cost,
|
|
count: 100,
|
|
},
|
|
},
|
|
}),
|
|
};
|
|
}
|
|
|
|
if (action === 'getNumber') {
|
|
return {
|
|
ok: true,
|
|
text: async () => `ACCESS_NUMBER:${country}001:44795500${country}`,
|
|
};
|
|
}
|
|
|
|
throw new Error(`Unexpected HeroSMS action: ${action} @ country ${country}`);
|
|
},
|
|
getState: async () => ({ heroSmsApiKey: 'demo-key', heroSmsCountryId: 52 }),
|
|
sendToContentScriptResilient: async () => ({}),
|
|
setState: async () => {},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const activation = await helpers.requestPhoneActivation({
|
|
heroSmsApiKey: 'demo-key',
|
|
heroSmsCountryId: 52,
|
|
heroSmsCountryLabel: 'Thailand',
|
|
heroSmsCountryFallback: [{ id: 16, label: 'United Kingdom' }],
|
|
heroSmsAcquirePriority: 'price',
|
|
});
|
|
|
|
assert.equal(activation.countryId, 16);
|
|
const actionTrace = requests.map((requestUrl) => `${requestUrl.searchParams.get('action')}:${requestUrl.searchParams.get('country')}`);
|
|
assert.deepStrictEqual(actionTrace, [
|
|
'getPrices:52',
|
|
'getPrices:16',
|
|
'getNumber:16',
|
|
]);
|
|
});
|
|
|
|
test('phone verification helper retries acquisition rounds when at least one country reports transient NO_NUMBERS', async () => {
|
|
const requests = [];
|
|
const logs = [];
|
|
const sleeps = [];
|
|
let thailandGetNumberCalls = 0;
|
|
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async (message, level) => {
|
|
logs.push({ message, level });
|
|
},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
const country = parsedUrl.searchParams.get('country');
|
|
|
|
if (action === 'getPrices') {
|
|
if (country === '52') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload({ country: '52', cost: 0.05, count: 20 }),
|
|
};
|
|
}
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload({ country, cost: 0.3, count: 20 }),
|
|
};
|
|
}
|
|
|
|
if (action === 'getNumber' || action === 'getNumberV2') {
|
|
if (country === '52') {
|
|
if (action === 'getNumber') {
|
|
thailandGetNumberCalls += 1;
|
|
if (thailandGetNumberCalls >= 2) {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_NUMBER:991122:66951112233',
|
|
};
|
|
}
|
|
}
|
|
return { ok: true, text: async () => 'NO_NUMBERS: Numbers Not Found. Try Later' };
|
|
}
|
|
return { ok: true, text: async () => 'NO_NUMBERS: Numbers Not Found. Try Later' };
|
|
}
|
|
|
|
throw new Error(`Unexpected HeroSMS action: ${action} @ country ${country}`);
|
|
},
|
|
getState: async () => ({ heroSmsApiKey: 'demo-key' }),
|
|
sendToContentScriptResilient: async () => ({}),
|
|
setState: async () => {},
|
|
sleepWithStop: async (ms) => {
|
|
sleeps.push(ms);
|
|
},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const activation = await helpers.requestPhoneActivation({
|
|
heroSmsApiKey: 'demo-key',
|
|
heroSmsMaxPrice: '0.06',
|
|
heroSmsCountryId: 52,
|
|
heroSmsCountryLabel: 'Thailand',
|
|
heroSmsCountryFallback: [
|
|
{ id: 6, label: 'Canada' },
|
|
{ id: 5, label: 'Japan' },
|
|
],
|
|
// Simulate stale state value; helper should still perform at least 2 rounds.
|
|
heroSmsActivationRetryRounds: 1,
|
|
});
|
|
|
|
assert.equal(activation.countryId, 52);
|
|
assert.equal(activation.phoneNumber, '66951112233');
|
|
assert.equal(sleeps.length, 1);
|
|
assert.equal(sleeps[0], 2000);
|
|
assert.equal(
|
|
logs.filter((entry) => String(entry.message || '').includes('HeroSMS acquiring phone number')).length >= 2,
|
|
true
|
|
);
|
|
assert.equal(
|
|
logs.some((entry) => String(entry.message || '').includes('HeroSMS has no available numbers (round 1/2); retrying')),
|
|
true
|
|
);
|
|
});
|
|
|
|
test('phone verification helper uses HeroSMS getStatusV2 after acquiring a number via getNumberV2', async () => {
|
|
const requests = [];
|
|
const stateUpdates = [];
|
|
let currentState = {
|
|
heroSmsApiKey: 'demo-key',
|
|
heroSmsCountryId: 16,
|
|
heroSmsCountryLabel: 'United Kingdom',
|
|
verificationResendCount: 0,
|
|
currentPhoneActivation: null,
|
|
reusablePhoneActivation: null,
|
|
};
|
|
let statusPollCount = 0;
|
|
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload({ country: '16' }),
|
|
};
|
|
}
|
|
if (action === 'getNumber') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'NO_NUMBERS',
|
|
};
|
|
}
|
|
if (action === 'getNumberV2') {
|
|
return {
|
|
ok: true,
|
|
text: async () => JSON.stringify({
|
|
activationId: '654321',
|
|
phoneNumber: '447911123456',
|
|
}),
|
|
};
|
|
}
|
|
if (action === 'getStatusV2') {
|
|
statusPollCount += 1;
|
|
return {
|
|
ok: true,
|
|
text: async () => (
|
|
statusPollCount === 1
|
|
? buildHeroSmsStatusV2Payload()
|
|
: buildHeroSmsStatusV2Payload({ smsCode: '112233', smsText: 'Your code is 112233' })
|
|
),
|
|
};
|
|
}
|
|
if (action === 'setStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_ACTIVATION',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
|
|
getState: async () => ({ ...currentState }),
|
|
sendToContentScriptResilient: async (_source, message) => {
|
|
if (message.type === 'SUBMIT_PHONE_NUMBER') {
|
|
return {
|
|
phoneVerificationPage: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
|
|
return {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected content-script message: ${message.type}`);
|
|
},
|
|
setState: async (updates) => {
|
|
stateUpdates.push(updates);
|
|
currentState = { ...currentState, ...updates };
|
|
},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const result = await helpers.completePhoneVerificationFlow(1, {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
});
|
|
|
|
assert.deepStrictEqual(result, {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
});
|
|
assert.equal(Array.isArray(stateUpdates[0]?.heroSmsLastPriceTiers), true);
|
|
assert.equal(stateUpdates[0]?.heroSmsLastPriceCountryId, 16);
|
|
assert.equal(stateUpdates[0]?.heroSmsLastPriceCountryLabel, 'United Kingdom');
|
|
assert.deepStrictEqual(stateUpdates.slice(1), [
|
|
{
|
|
currentPhoneActivation: {
|
|
activationId: '654321',
|
|
phoneNumber: '447911123456',
|
|
provider: 'hero-sms',
|
|
serviceCode: 'dr',
|
|
countryId: 16,
|
|
successfulUses: 0,
|
|
maxUses: 3,
|
|
statusAction: 'getStatusV2',
|
|
},
|
|
currentPhoneVerificationCode: '',
|
|
},
|
|
{
|
|
currentPhoneVerificationCode: '112233',
|
|
},
|
|
{
|
|
reusablePhoneActivation: {
|
|
activationId: '654321',
|
|
phoneNumber: '447911123456',
|
|
provider: 'hero-sms',
|
|
serviceCode: 'dr',
|
|
countryId: 16,
|
|
successfulUses: 1,
|
|
maxUses: 3,
|
|
statusAction: 'getStatusV2',
|
|
},
|
|
},
|
|
{
|
|
currentPhoneActivation: null,
|
|
currentPhoneVerificationCode: '',
|
|
},
|
|
]);
|
|
const actions = requests.map((url) => url.searchParams.get('action'));
|
|
assert.deepStrictEqual(actions, [
|
|
'getPrices',
|
|
'getNumber',
|
|
'getNumberV2',
|
|
'getStatusV2',
|
|
'getStatusV2',
|
|
'setStatus',
|
|
]);
|
|
});
|
|
|
|
test('phone verification helper refreshes maxPrice when HeroSMS returns WRONG_MAX_PRICE', async () => {
|
|
const requests = [];
|
|
let getNumberAttempt = 0;
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload(),
|
|
};
|
|
}
|
|
if (action === 'getNumber') {
|
|
getNumberAttempt += 1;
|
|
return getNumberAttempt === 1
|
|
? {
|
|
ok: false,
|
|
text: async () => 'WRONG_MAX_PRICE:0.09',
|
|
}
|
|
: {
|
|
ok: true,
|
|
text: async () => 'ACCESS_NUMBER:123456:66959916439',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getState: async () => ({ heroSmsApiKey: 'demo-key' }),
|
|
sendToContentScriptResilient: async () => ({}),
|
|
setState: async () => {},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const activation = await helpers.requestPhoneActivation({ heroSmsApiKey: 'demo-key' });
|
|
|
|
assert.deepStrictEqual(activation, {
|
|
activationId: '123456',
|
|
phoneNumber: '66959916439',
|
|
provider: 'hero-sms',
|
|
serviceCode: 'dr',
|
|
countryId: 52,
|
|
successfulUses: 0,
|
|
maxUses: 3,
|
|
});
|
|
assert.equal(requests.length, 3);
|
|
assert.equal(requests[0].searchParams.get('action'), 'getPrices');
|
|
assert.equal(requests[1].searchParams.get('action'), 'getNumber');
|
|
assert.equal(requests[1].searchParams.get('maxPrice'), '0.08');
|
|
assert.equal(requests[2].searchParams.get('action'), 'getNumber');
|
|
assert.equal(requests[2].searchParams.get('maxPrice'), '0.09');
|
|
assert.equal(requests[2].searchParams.get('fixedPrice'), 'true');
|
|
});
|
|
|
|
test('phone verification helper climbs price tiers when NO_NUMBERS is returned at lower prices', async () => {
|
|
const requests = [];
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
const maxPrice = parsedUrl.searchParams.get('maxPrice');
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => JSON.stringify({
|
|
52: {
|
|
dr: {
|
|
starter: { cost: 0.08, count: 100 },
|
|
premium: { cost: 0.12, count: 100 },
|
|
},
|
|
},
|
|
}),
|
|
};
|
|
}
|
|
if (action === 'getNumber' && maxPrice === '0.08') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'NO_NUMBERS',
|
|
};
|
|
}
|
|
if (action === 'getNumberV2' && maxPrice === '0.08') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'NO_NUMBERS',
|
|
};
|
|
}
|
|
if (action === 'getNumber' && maxPrice === '0.12') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_NUMBER:989898:66951112222',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action} @ ${maxPrice || 'no-price'}`);
|
|
},
|
|
getState: async () => ({ heroSmsApiKey: 'demo-key' }),
|
|
sendToContentScriptResilient: async () => ({}),
|
|
setState: async () => {},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const activation = await helpers.requestPhoneActivation({ heroSmsApiKey: 'demo-key' });
|
|
assert.equal(activation.activationId, '989898');
|
|
const actions = requests.map((requestUrl) => `${requestUrl.searchParams.get('action')}:${requestUrl.searchParams.get('maxPrice') || ''}`);
|
|
assert.deepStrictEqual(actions, [
|
|
'getPrices:',
|
|
'getNumber:0.08',
|
|
'getNumberV2:0.08',
|
|
'getNumber:0.12',
|
|
]);
|
|
});
|
|
|
|
test('phone verification helper stops when WRONG_MAX_PRICE exceeds configured max price limit', async () => {
|
|
const requests = [];
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload({ cost: 0.08 }),
|
|
};
|
|
}
|
|
if (action === 'getNumber' || action === 'getNumberV2') {
|
|
return {
|
|
ok: false,
|
|
text: async () => 'WRONG_MAX_PRICE:0.08',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getState: async () => ({ heroSmsApiKey: 'demo-key', heroSmsMaxPrice: '0.05' }),
|
|
sendToContentScriptResilient: async () => ({}),
|
|
setState: async () => {},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
await assert.rejects(
|
|
helpers.requestPhoneActivation({ heroSmsApiKey: 'demo-key', heroSmsMaxPrice: '0.05' }),
|
|
/exceeds configured maxPrice=0\.05/i
|
|
);
|
|
|
|
const actions = requests.map((requestUrl) => `${requestUrl.searchParams.get('action')}:${requestUrl.searchParams.get('maxPrice') || ''}`);
|
|
assert.deepStrictEqual(actions, [
|
|
'getPrices:',
|
|
'getNumber:0.05',
|
|
'getNumberV2:0.05',
|
|
]);
|
|
});
|
|
|
|
test('phone verification helper falls back to plain getNumber when priced request fails to fetch', async () => {
|
|
const requests = [];
|
|
let getNumberAttempt = 0;
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload(),
|
|
};
|
|
}
|
|
if (action === 'getNumber') {
|
|
getNumberAttempt += 1;
|
|
if (getNumberAttempt === 1) {
|
|
throw new TypeError('Failed to fetch');
|
|
}
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_NUMBER:123456:66959916439',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getState: async () => ({ heroSmsApiKey: 'demo-key' }),
|
|
sendToContentScriptResilient: async () => ({}),
|
|
setState: async () => {},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const activation = await helpers.requestPhoneActivation({ heroSmsApiKey: 'demo-key' });
|
|
|
|
assert.deepStrictEqual(activation, {
|
|
activationId: '123456',
|
|
phoneNumber: '66959916439',
|
|
provider: 'hero-sms',
|
|
serviceCode: 'dr',
|
|
countryId: 52,
|
|
successfulUses: 0,
|
|
maxUses: 3,
|
|
});
|
|
assert.equal(requests.length, 3);
|
|
assert.equal(requests[0].searchParams.get('action'), 'getPrices');
|
|
assert.equal(requests[1].searchParams.get('action'), 'getNumber');
|
|
assert.equal(requests[1].searchParams.get('maxPrice'), '0.08');
|
|
assert.equal(requests[1].searchParams.get('fixedPrice'), 'true');
|
|
assert.equal(requests[2].searchParams.get('action'), 'getNumber');
|
|
assert.equal(requests[2].searchParams.get('maxPrice'), null);
|
|
assert.equal(requests[2].searchParams.get('fixedPrice'), null);
|
|
});
|
|
|
|
test('phone verification helper completes add-phone flow, clears current activation, and stores reusable number state', async () => {
|
|
const requests = [];
|
|
const stateUpdates = [];
|
|
let currentState = {
|
|
heroSmsApiKey: 'demo-key',
|
|
verificationResendCount: 1,
|
|
currentPhoneActivation: null,
|
|
reusablePhoneActivation: null,
|
|
};
|
|
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload(),
|
|
};
|
|
}
|
|
if (action === 'getNumber') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_NUMBER:123456:66959916439',
|
|
};
|
|
}
|
|
if (action === 'getStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'STATUS_OK:654321',
|
|
};
|
|
}
|
|
if (action === 'setStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_ACTIVATION',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
|
|
getState: async () => ({ ...currentState }),
|
|
sendToContentScriptResilient: async (_source, message) => {
|
|
if (message.type === 'SUBMIT_PHONE_NUMBER') {
|
|
return {
|
|
phoneVerificationPage: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
|
|
return {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected content-script message: ${message.type}`);
|
|
},
|
|
setState: async (updates) => {
|
|
stateUpdates.push(updates);
|
|
currentState = { ...currentState, ...updates };
|
|
},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const result = await helpers.completePhoneVerificationFlow(1, {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
});
|
|
|
|
assert.deepStrictEqual(result, {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
});
|
|
assert.equal(Array.isArray(stateUpdates[0]?.heroSmsLastPriceTiers), true);
|
|
assert.equal(stateUpdates[0]?.heroSmsLastPriceCountryId, 52);
|
|
assert.equal(stateUpdates[0]?.heroSmsLastPriceCountryLabel, 'Thailand');
|
|
assert.deepStrictEqual(stateUpdates.slice(1), [
|
|
{
|
|
currentPhoneActivation: {
|
|
activationId: '123456',
|
|
phoneNumber: '66959916439',
|
|
provider: 'hero-sms',
|
|
serviceCode: 'dr',
|
|
countryId: 52,
|
|
successfulUses: 0,
|
|
maxUses: 3,
|
|
},
|
|
currentPhoneVerificationCode: '',
|
|
},
|
|
{
|
|
currentPhoneVerificationCode: '654321',
|
|
},
|
|
{
|
|
reusablePhoneActivation: {
|
|
activationId: '123456',
|
|
phoneNumber: '66959916439',
|
|
provider: 'hero-sms',
|
|
serviceCode: 'dr',
|
|
countryId: 52,
|
|
successfulUses: 1,
|
|
maxUses: 3,
|
|
},
|
|
},
|
|
{
|
|
currentPhoneActivation: null,
|
|
currentPhoneVerificationCode: '',
|
|
},
|
|
]);
|
|
|
|
const actions = requests.map((url) => url.searchParams.get('action'));
|
|
assert.deepStrictEqual(actions, ['getPrices', 'getNumber', 'getStatus', 'setStatus']);
|
|
});
|
|
|
|
test('phone verification helper uses the configured HeroSMS country for both number acquisition and add-phone submission', async () => {
|
|
const requests = [];
|
|
const submittedPayloads = [];
|
|
let currentState = {
|
|
heroSmsApiKey: 'demo-key',
|
|
heroSmsCountryId: 16,
|
|
heroSmsCountryLabel: 'United Kingdom',
|
|
verificationResendCount: 0,
|
|
currentPhoneActivation: null,
|
|
reusablePhoneActivation: null,
|
|
};
|
|
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload({ country: '16' }),
|
|
};
|
|
}
|
|
if (action === 'getNumber') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_NUMBER:654321:447911123456',
|
|
};
|
|
}
|
|
if (action === 'getStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'STATUS_OK:112233',
|
|
};
|
|
}
|
|
if (action === 'setStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_ACTIVATION',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
|
|
getState: async () => ({ ...currentState }),
|
|
sendToContentScriptResilient: async (_source, message) => {
|
|
if (message.type === 'SUBMIT_PHONE_NUMBER') {
|
|
submittedPayloads.push(message.payload);
|
|
return {
|
|
phoneVerificationPage: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
|
|
return {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected content-script message: ${message.type}`);
|
|
},
|
|
setState: async (updates) => {
|
|
currentState = { ...currentState, ...updates };
|
|
},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const result = await helpers.completePhoneVerificationFlow(1, {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
});
|
|
|
|
assert.deepStrictEqual(result, {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
});
|
|
assert.equal(requests[0].searchParams.get('action'), 'getPrices');
|
|
assert.equal(requests[0].searchParams.get('country'), '16');
|
|
assert.equal(requests[1].searchParams.get('action'), 'getNumber');
|
|
assert.equal(requests[1].searchParams.get('country'), '16');
|
|
assert.equal(requests[1].searchParams.get('maxPrice'), '0.08');
|
|
assert.equal(requests[1].searchParams.get('fixedPrice'), 'true');
|
|
assert.deepStrictEqual(submittedPayloads, [{
|
|
phoneNumber: '447911123456',
|
|
countryId: 16,
|
|
countryLabel: 'United Kingdom',
|
|
}]);
|
|
});
|
|
|
|
test('phone verification helper skips reusable activation when reuse toggle is disabled', async () => {
|
|
const requests = [];
|
|
let currentState = {
|
|
heroSmsApiKey: 'demo-key',
|
|
heroSmsReuseEnabled: false,
|
|
verificationResendCount: 0,
|
|
currentPhoneActivation: null,
|
|
reusablePhoneActivation: {
|
|
activationId: 'reuse-001',
|
|
phoneNumber: '66950012345',
|
|
provider: 'hero-sms',
|
|
serviceCode: 'dr',
|
|
countryId: 52,
|
|
successfulUses: 0,
|
|
maxUses: 3,
|
|
},
|
|
};
|
|
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'reactivate') {
|
|
throw new Error('reactivate should not be called when reuse is disabled');
|
|
}
|
|
if (action === 'getPrices') {
|
|
return { ok: true, text: async () => buildHeroSmsPricesPayload() };
|
|
}
|
|
if (action === 'getNumber') {
|
|
return { ok: true, text: async () => 'ACCESS_NUMBER:900001:66958887777' };
|
|
}
|
|
if (action === 'getStatus') {
|
|
return { ok: true, text: async () => 'STATUS_OK:777111' };
|
|
}
|
|
if (action === 'setStatus') {
|
|
return { ok: true, text: async () => 'STATUS_UPDATED' };
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
|
|
getState: async () => ({ ...currentState }),
|
|
sendToContentScriptResilient: async (_source, message) => {
|
|
if (message.type === 'SUBMIT_PHONE_NUMBER') {
|
|
return {
|
|
phoneVerificationPage: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
|
|
return {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected content-script message: ${message.type}`);
|
|
},
|
|
setState: async (updates) => {
|
|
currentState = { ...currentState, ...updates };
|
|
},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const result = await helpers.completePhoneVerificationFlow(1, {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
});
|
|
|
|
assert.equal(result.success, true);
|
|
assert.equal(requests.some((requestUrl) => requestUrl.searchParams.get('action') === 'reactivate'), false);
|
|
assert.equal(currentState.reusablePhoneActivation, null);
|
|
});
|
|
|
|
test('phone verification helper replaces numbers in step 9 and stops after replacement limit when SMS never arrives', async () => {
|
|
const requests = [];
|
|
const messages = [];
|
|
let currentState = {
|
|
heroSmsApiKey: 'demo-key',
|
|
verificationResendCount: 0,
|
|
currentPhoneActivation: null,
|
|
reusablePhoneActivation: null,
|
|
};
|
|
const statusCallsById = {};
|
|
const realDateNow = Date.now;
|
|
let fakeNow = 0;
|
|
Date.now = () => fakeNow;
|
|
|
|
try {
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
const id = parsedUrl.searchParams.get('id');
|
|
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload(),
|
|
};
|
|
}
|
|
|
|
if (action === 'getNumber') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_NUMBER:123456:66959916439',
|
|
};
|
|
}
|
|
|
|
if (action === 'getStatus') {
|
|
statusCallsById[id] = (statusCallsById[id] || 0) + 1;
|
|
return {
|
|
ok: true,
|
|
text: async () => 'STATUS_WAIT_CODE',
|
|
};
|
|
}
|
|
|
|
if (action === 'setStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_ACTIVATION',
|
|
};
|
|
}
|
|
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
|
|
getState: async () => ({ ...currentState }),
|
|
sendToContentScriptResilient: async (_source, message) => {
|
|
messages.push(message.type);
|
|
if (message.type === 'SUBMIT_PHONE_NUMBER') {
|
|
return {
|
|
phoneVerificationPage: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'RESEND_PHONE_VERIFICATION_CODE') {
|
|
return {
|
|
resent: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected content-script message: ${message.type}`);
|
|
},
|
|
setState: async (updates) => {
|
|
currentState = { ...currentState, ...updates };
|
|
},
|
|
sleepWithStop: async () => {
|
|
fakeNow += 61000;
|
|
},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
await assert.rejects(
|
|
helpers.completePhoneVerificationFlow(1, {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
}),
|
|
/did not succeed after 3 number replacements/i
|
|
);
|
|
assert.ok(statusCallsById['123456'] >= 2, 'first number should be polled twice before being replaced');
|
|
assert.ok(messages.includes('SUBMIT_PHONE_NUMBER'));
|
|
assert.ok(messages.includes('RESEND_PHONE_VERIFICATION_CODE'));
|
|
assert.ok(messages.filter((type) => type === 'SUBMIT_PHONE_NUMBER').length > 1);
|
|
|
|
const actions = requests.map((url) => `${url.searchParams.get('action')}:${url.searchParams.get('id') || ''}`);
|
|
assert.ok(actions.filter((action) => action === 'getNumber:').length > 1);
|
|
assert.ok(actions.filter((action) => action === 'getStatus:123456').length >= 2);
|
|
assert.ok(actions.filter((action) => action === 'setStatus:123456').length >= 2);
|
|
assert.equal(currentState.currentPhoneActivation, null);
|
|
} finally {
|
|
Date.now = realDateNow;
|
|
}
|
|
});
|
|
|
|
test('phone verification helper honors timeout-window and poll-round settings before replacing numbers', async () => {
|
|
const requests = [];
|
|
const messages = [];
|
|
let currentState = {
|
|
heroSmsApiKey: 'demo-key',
|
|
verificationResendCount: 0,
|
|
phoneVerificationReplacementLimit: 1,
|
|
phoneCodeWaitSeconds: 60,
|
|
phoneCodeTimeoutWindows: 1,
|
|
phoneCodePollIntervalSeconds: 1,
|
|
phoneCodePollMaxRounds: 1,
|
|
currentPhoneActivation: null,
|
|
reusablePhoneActivation: null,
|
|
};
|
|
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'getPrices') {
|
|
return { ok: true, text: async () => buildHeroSmsPricesPayload() };
|
|
}
|
|
if (action === 'getNumber') {
|
|
return { ok: true, text: async () => 'ACCESS_NUMBER:500001:66957776666' };
|
|
}
|
|
if (action === 'getStatus') {
|
|
return { ok: true, text: async () => 'STATUS_WAIT_CODE' };
|
|
}
|
|
if (action === 'setStatus') {
|
|
return { ok: true, text: async () => 'STATUS_UPDATED' };
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
|
|
getState: async () => ({ ...currentState }),
|
|
sendToContentScriptResilient: async (_source, message) => {
|
|
messages.push(message.type);
|
|
if (message.type === 'SUBMIT_PHONE_NUMBER') {
|
|
return {
|
|
phoneVerificationPage: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'RETURN_TO_ADD_PHONE') {
|
|
return {
|
|
addPhonePage: true,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
};
|
|
}
|
|
if (message.type === 'RESEND_PHONE_VERIFICATION_CODE') {
|
|
throw new Error('resend should not be called when timeout windows is 1');
|
|
}
|
|
throw new Error(`Unexpected content-script message: ${message.type}`);
|
|
},
|
|
setState: async (updates) => {
|
|
currentState = { ...currentState, ...updates };
|
|
},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
await assert.rejects(
|
|
helpers.completePhoneVerificationFlow(1, {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
}),
|
|
/did not succeed after 1 number replacements/i
|
|
);
|
|
|
|
assert.equal(messages.includes('RESEND_PHONE_VERIFICATION_CODE'), false);
|
|
assert.ok(
|
|
requests.filter((requestUrl) => requestUrl.searchParams.get('action') === 'getStatus').length >= 2,
|
|
'each replacement attempt should still poll HeroSMS at least once'
|
|
);
|
|
});
|
|
|
|
test('phone verification helper respects configured number replacement limit', async () => {
|
|
const requests = [];
|
|
let currentState = {
|
|
heroSmsApiKey: 'demo-key',
|
|
verificationResendCount: 0,
|
|
phoneVerificationReplacementLimit: 1,
|
|
currentPhoneActivation: null,
|
|
reusablePhoneActivation: null,
|
|
};
|
|
let submitCodeCount = 0;
|
|
const numbers = [
|
|
{ activationId: '411111', phoneNumber: '66950000111' },
|
|
{ activationId: '422222', phoneNumber: '66950000222' },
|
|
];
|
|
let numberIndex = 0;
|
|
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
const id = parsedUrl.searchParams.get('id');
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload(),
|
|
};
|
|
}
|
|
if (action === 'getNumber') {
|
|
const nextNumber = numbers[numberIndex];
|
|
numberIndex += 1;
|
|
return {
|
|
ok: true,
|
|
text: async () => `ACCESS_NUMBER:${nextNumber.activationId}:${nextNumber.phoneNumber}`,
|
|
};
|
|
}
|
|
if (action === 'getStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'STATUS_OK:654321',
|
|
};
|
|
}
|
|
if (action === 'setStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => `STATUS_UPDATED:${id}`,
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
|
|
getState: async () => ({ ...currentState }),
|
|
sendToContentScriptResilient: async (_source, message) => {
|
|
if (message.type === 'SUBMIT_PHONE_NUMBER') {
|
|
return {
|
|
phoneVerificationPage: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
|
|
submitCodeCount += 1;
|
|
return {
|
|
invalidCode: true,
|
|
errorText: `This phone number is already linked to the maximum number of accounts. (${submitCodeCount})`,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'RETURN_TO_ADD_PHONE') {
|
|
return {
|
|
addPhonePage: true,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected content-script message: ${message.type}`);
|
|
},
|
|
setState: async (updates) => {
|
|
currentState = { ...currentState, ...updates };
|
|
},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
await assert.rejects(
|
|
helpers.completePhoneVerificationFlow(1, {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
}),
|
|
/did not succeed after 1 number replacements/i
|
|
);
|
|
|
|
const actions = requests.map((requestUrl) => requestUrl.searchParams.get('action'));
|
|
assert.deepStrictEqual(actions, [
|
|
'getPrices',
|
|
'getNumber',
|
|
'getStatus',
|
|
'setStatus',
|
|
'getPrices',
|
|
'getNumber',
|
|
'getStatus',
|
|
'setStatus',
|
|
]);
|
|
});
|
|
|
|
test('phone verification helper reuses the current number first when code submission returns to add-phone', async () => {
|
|
const requests = [];
|
|
const messages = [];
|
|
let currentState = {
|
|
heroSmsApiKey: 'demo-key',
|
|
verificationResendCount: 1,
|
|
currentPhoneActivation: null,
|
|
reusablePhoneActivation: null,
|
|
};
|
|
|
|
const numbers = [
|
|
{ activationId: '111111', phoneNumber: '66950000001' },
|
|
{ activationId: '222222', phoneNumber: '66950000002' },
|
|
];
|
|
let numberIndex = 0;
|
|
let submitCodeCount = 0;
|
|
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
const id = parsedUrl.searchParams.get('id');
|
|
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload(),
|
|
};
|
|
}
|
|
|
|
if (action === 'getNumber') {
|
|
const nextNumber = numbers[numberIndex];
|
|
numberIndex += 1;
|
|
return {
|
|
ok: true,
|
|
text: async () => `ACCESS_NUMBER:${nextNumber.activationId}:${nextNumber.phoneNumber}`,
|
|
};
|
|
}
|
|
if (action === 'getStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'STATUS_OK:654321',
|
|
};
|
|
}
|
|
if (action === 'setStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => `STATUS_UPDATED:${id}`,
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
|
|
getState: async () => ({ ...currentState }),
|
|
sendToContentScriptResilient: async (_source, message) => {
|
|
messages.push(message.type);
|
|
if (message.type === 'SUBMIT_PHONE_NUMBER') {
|
|
return {
|
|
phoneVerificationPage: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
|
|
submitCodeCount += 1;
|
|
return submitCodeCount === 1
|
|
? {
|
|
returnedToAddPhone: true,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
}
|
|
: {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
};
|
|
}
|
|
if (message.type === 'RESEND_PHONE_VERIFICATION_CODE') {
|
|
return {
|
|
resent: true,
|
|
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: () => {},
|
|
});
|
|
|
|
const result = await helpers.completePhoneVerificationFlow(1, {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
});
|
|
|
|
assert.deepStrictEqual(result, {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
});
|
|
assert.deepStrictEqual(messages, [
|
|
'SUBMIT_PHONE_NUMBER',
|
|
'SUBMIT_PHONE_VERIFICATION_CODE',
|
|
'SUBMIT_PHONE_NUMBER',
|
|
'SUBMIT_PHONE_VERIFICATION_CODE',
|
|
]);
|
|
|
|
const actions = requests.map((url) => `${url.searchParams.get('action')}:${url.searchParams.get('id') || ''}`);
|
|
assert.deepStrictEqual(actions, [
|
|
'getPrices:',
|
|
'getNumber:',
|
|
'getStatus:111111',
|
|
'getStatus:111111',
|
|
'setStatus:111111',
|
|
]);
|
|
assert.deepStrictEqual(currentState.currentPhoneActivation, null);
|
|
assert.deepStrictEqual(currentState.reusablePhoneActivation, {
|
|
activationId: '111111',
|
|
phoneNumber: '66950000001',
|
|
provider: 'hero-sms',
|
|
serviceCode: 'dr',
|
|
countryId: 52,
|
|
successfulUses: 1,
|
|
maxUses: 3,
|
|
});
|
|
});
|
|
|
|
test('phone verification helper immediately replaces number when page says the phone number was already used', async () => {
|
|
const requests = [];
|
|
const messages = [];
|
|
let currentState = {
|
|
heroSmsApiKey: 'demo-key',
|
|
verificationResendCount: 1,
|
|
currentPhoneActivation: null,
|
|
reusablePhoneActivation: null,
|
|
};
|
|
|
|
const numbers = [
|
|
{ activationId: '311111', phoneNumber: '66950000011' },
|
|
{ activationId: '322222', phoneNumber: '66950000022' },
|
|
];
|
|
let numberIndex = 0;
|
|
let submitCodeCount = 0;
|
|
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
const id = parsedUrl.searchParams.get('id');
|
|
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsPricesPayload(),
|
|
};
|
|
}
|
|
if (action === 'getNumber') {
|
|
const nextNumber = numbers[numberIndex];
|
|
numberIndex += 1;
|
|
return {
|
|
ok: true,
|
|
text: async () => `ACCESS_NUMBER:${nextNumber.activationId}:${nextNumber.phoneNumber}`,
|
|
};
|
|
}
|
|
if (action === 'getStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'STATUS_OK:654321',
|
|
};
|
|
}
|
|
if (action === 'setStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => `STATUS_UPDATED:${id}`,
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
|
|
getState: async () => ({ ...currentState }),
|
|
sendToContentScriptResilient: async (_source, message) => {
|
|
messages.push(message.type);
|
|
if (message.type === 'SUBMIT_PHONE_NUMBER') {
|
|
return {
|
|
phoneVerificationPage: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
|
|
submitCodeCount += 1;
|
|
if (submitCodeCount === 1) {
|
|
return {
|
|
invalidCode: true,
|
|
errorText: 'This phone number is already linked to the maximum number of accounts.',
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
return {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
};
|
|
}
|
|
if (message.type === 'RETURN_TO_ADD_PHONE') {
|
|
return {
|
|
addPhonePage: true,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
};
|
|
}
|
|
if (message.type === 'RESEND_PHONE_VERIFICATION_CODE') {
|
|
throw new Error('should not resend for already-used number');
|
|
}
|
|
throw new Error(`Unexpected content-script message: ${message.type}`);
|
|
},
|
|
setState: async (updates) => {
|
|
currentState = { ...currentState, ...updates };
|
|
},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const result = await helpers.completePhoneVerificationFlow(1, {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
});
|
|
|
|
assert.deepStrictEqual(result, {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
});
|
|
assert.deepStrictEqual(messages, [
|
|
'SUBMIT_PHONE_NUMBER',
|
|
'SUBMIT_PHONE_VERIFICATION_CODE',
|
|
'RETURN_TO_ADD_PHONE',
|
|
'SUBMIT_PHONE_NUMBER',
|
|
'SUBMIT_PHONE_VERIFICATION_CODE',
|
|
]);
|
|
});
|
|
|
|
test('phone verification helper reuses the same number up to three successful registrations', async () => {
|
|
const requests = [];
|
|
let currentState = {
|
|
heroSmsApiKey: 'demo-key',
|
|
verificationResendCount: 0,
|
|
currentPhoneActivation: null,
|
|
reusablePhoneActivation: {
|
|
activationId: '123456',
|
|
phoneNumber: '66959916439',
|
|
provider: 'hero-sms',
|
|
serviceCode: 'dr',
|
|
countryId: 52,
|
|
successfulUses: 2,
|
|
maxUses: 3,
|
|
},
|
|
};
|
|
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'reactivate') {
|
|
return {
|
|
ok: true,
|
|
text: async () => JSON.stringify({
|
|
activationId: '222333',
|
|
phoneNumber: '66959916439',
|
|
}),
|
|
};
|
|
}
|
|
if (action === 'getStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'STATUS_OK:654321',
|
|
};
|
|
}
|
|
if (action === 'setStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_ACTIVATION',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
|
|
getState: async () => ({ ...currentState }),
|
|
sendToContentScriptResilient: async (_source, message) => {
|
|
if (message.type === 'SUBMIT_PHONE_NUMBER') {
|
|
return {
|
|
phoneVerificationPage: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
|
|
return {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected content-script message: ${message.type}`);
|
|
},
|
|
setState: async (updates) => {
|
|
currentState = { ...currentState, ...updates };
|
|
},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const result = await helpers.completePhoneVerificationFlow(1, {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
});
|
|
|
|
assert.deepStrictEqual(result, {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
});
|
|
assert.equal(requests[0].searchParams.get('action'), 'reactivate');
|
|
assert.equal(requests[0].searchParams.get('id'), '123456');
|
|
assert.deepStrictEqual(currentState.reusablePhoneActivation, null);
|
|
});
|
|
|
|
test('phone verification helper keeps maxUses behavior for reused V2 activations', async () => {
|
|
const requests = [];
|
|
let currentState = {
|
|
heroSmsApiKey: 'demo-key',
|
|
heroSmsCountryId: 16,
|
|
heroSmsCountryLabel: 'United Kingdom',
|
|
verificationResendCount: 0,
|
|
currentPhoneActivation: null,
|
|
reusablePhoneActivation: {
|
|
activationId: '123456',
|
|
phoneNumber: '447911123456',
|
|
provider: 'hero-sms',
|
|
serviceCode: 'dr',
|
|
countryId: 16,
|
|
successfulUses: 2,
|
|
maxUses: 3,
|
|
statusAction: 'getStatusV2',
|
|
},
|
|
};
|
|
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
if (action === 'reactivate') {
|
|
return {
|
|
ok: true,
|
|
text: async () => JSON.stringify({
|
|
activationId: '222333',
|
|
phoneNumber: '447911123456',
|
|
}),
|
|
};
|
|
}
|
|
if (action === 'getStatusV2') {
|
|
return {
|
|
ok: true,
|
|
text: async () => buildHeroSmsStatusV2Payload({ smsCode: '654321', smsText: 'Your code is 654321' }),
|
|
};
|
|
}
|
|
if (action === 'setStatus') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_ACTIVATION',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
|
|
getState: async () => ({ ...currentState }),
|
|
sendToContentScriptResilient: async (_source, message) => {
|
|
if (message.type === 'SUBMIT_PHONE_NUMBER') {
|
|
return {
|
|
phoneVerificationPage: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
|
|
return {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected content-script message: ${message.type}`);
|
|
},
|
|
setState: async (updates) => {
|
|
currentState = { ...currentState, ...updates };
|
|
},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const result = await helpers.completePhoneVerificationFlow(1, {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
});
|
|
|
|
assert.deepStrictEqual(result, {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
});
|
|
const actions = requests.map((url) => url.searchParams.get('action'));
|
|
assert.deepStrictEqual(actions, ['reactivate', 'getStatusV2', 'setStatus']);
|
|
assert.deepStrictEqual(currentState.reusablePhoneActivation, null);
|
|
});
|
|
|
|
test('phone verification helper replaces number immediately when resend is throttled and does not spam resend clicks', async () => {
|
|
const requests = [];
|
|
const messages = [];
|
|
let resendCalls = 0;
|
|
let currentState = {
|
|
heroSmsApiKey: 'demo-key',
|
|
heroSmsCountryId: 52,
|
|
heroSmsCountryLabel: 'Thailand',
|
|
verificationResendCount: 0,
|
|
phoneVerificationReplacementLimit: 2,
|
|
phoneCodeWaitSeconds: 60,
|
|
phoneCodeTimeoutWindows: 3,
|
|
phoneCodePollIntervalSeconds: 1,
|
|
phoneCodePollMaxRounds: 1,
|
|
currentPhoneActivation: null,
|
|
reusablePhoneActivation: null,
|
|
};
|
|
|
|
const numbers = [
|
|
{ activationId: '900001', phoneNumber: '66951110001' },
|
|
{ activationId: '900002', phoneNumber: '66951110002' },
|
|
];
|
|
let numberIndex = 0;
|
|
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
const id = parsedUrl.searchParams.get('id');
|
|
if (action === 'getPrices') {
|
|
return { ok: true, text: async () => buildHeroSmsPricesPayload() };
|
|
}
|
|
if (action === 'getNumber') {
|
|
const nextNumber = numbers[numberIndex];
|
|
numberIndex += 1;
|
|
return { ok: true, text: async () => `ACCESS_NUMBER:${nextNumber.activationId}:${nextNumber.phoneNumber}` };
|
|
}
|
|
if (action === 'getStatus') {
|
|
if (id === '900001') {
|
|
return { ok: true, text: async () => 'STATUS_WAIT_CODE' };
|
|
}
|
|
return { ok: true, text: async () => 'STATUS_OK:654321' };
|
|
}
|
|
if (action === 'setStatus') {
|
|
return { ok: true, text: async () => `STATUS_UPDATED:${id}` };
|
|
}
|
|
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
|
},
|
|
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
|
|
getState: async () => ({ ...currentState }),
|
|
sendToContentScriptResilient: async (_source, message) => {
|
|
messages.push(message.type);
|
|
if (message.type === 'SUBMIT_PHONE_NUMBER') {
|
|
return {
|
|
phoneVerificationPage: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'RESEND_PHONE_VERIFICATION_CODE') {
|
|
resendCalls += 1;
|
|
throw new Error('PHONE_RESEND_THROTTLED::Tried to resend too many times. Please try again later.');
|
|
}
|
|
if (message.type === 'RETURN_TO_ADD_PHONE') {
|
|
return {
|
|
addPhonePage: true,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
};
|
|
}
|
|
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
|
|
return {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected content-script message: ${message.type}`);
|
|
},
|
|
setState: async (updates) => {
|
|
currentState = { ...currentState, ...updates };
|
|
},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const result = await helpers.completePhoneVerificationFlow(1, {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
});
|
|
|
|
assert.deepStrictEqual(result, {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
});
|
|
assert.equal(resendCalls, 1, 'resend should be attempted once for the number before replacement');
|
|
assert.equal(messages.filter((type) => type === 'SUBMIT_PHONE_NUMBER').length, 2);
|
|
assert.equal(messages.includes('RETURN_TO_ADD_PHONE'), true);
|
|
});
|
|
|
|
test('phone verification helper falls back to the next country after repeated sms timeout on the same country', async () => {
|
|
const requests = [];
|
|
let currentState = {
|
|
heroSmsApiKey: 'demo-key',
|
|
heroSmsCountryId: 52,
|
|
heroSmsCountryLabel: 'Thailand',
|
|
heroSmsCountryFallback: [{ id: 16, label: 'United Kingdom' }],
|
|
verificationResendCount: 0,
|
|
phoneVerificationReplacementLimit: 3,
|
|
phoneCodeWaitSeconds: 60,
|
|
phoneCodeTimeoutWindows: 1,
|
|
phoneCodePollIntervalSeconds: 1,
|
|
phoneCodePollMaxRounds: 1,
|
|
currentPhoneActivation: null,
|
|
reusablePhoneActivation: null,
|
|
};
|
|
|
|
let thailandAcquireIndex = 0;
|
|
|
|
const helpers = api.createPhoneVerificationHelpers({
|
|
addLog: async () => {},
|
|
ensureStep8SignupPageReady: async () => {},
|
|
fetchImpl: async (url) => {
|
|
const parsedUrl = new URL(url);
|
|
requests.push(parsedUrl);
|
|
const action = parsedUrl.searchParams.get('action');
|
|
const id = parsedUrl.searchParams.get('id');
|
|
const country = parsedUrl.searchParams.get('country');
|
|
|
|
if (action === 'getPrices') {
|
|
return {
|
|
ok: true,
|
|
text: async () => JSON.stringify({
|
|
[country]: {
|
|
dr: {
|
|
cost: country === '52' ? 0.08 : 0.09,
|
|
count: 100,
|
|
},
|
|
},
|
|
}),
|
|
};
|
|
}
|
|
|
|
if (action === 'getNumber') {
|
|
if (country === '52') {
|
|
thailandAcquireIndex += 1;
|
|
return {
|
|
ok: true,
|
|
text: async () => `ACCESS_NUMBER:52${thailandAcquireIndex}:66950000${thailandAcquireIndex}`,
|
|
};
|
|
}
|
|
if (country === '16') {
|
|
return {
|
|
ok: true,
|
|
text: async () => 'ACCESS_NUMBER:160001:447955001122',
|
|
};
|
|
}
|
|
}
|
|
|
|
if (action === 'getStatus') {
|
|
if (id === '160001') {
|
|
return { ok: true, text: async () => 'STATUS_OK:888999' };
|
|
}
|
|
return { ok: true, text: async () => 'STATUS_WAIT_CODE' };
|
|
}
|
|
|
|
if (action === 'setStatus') {
|
|
return { ok: true, text: async () => 'STATUS_UPDATED' };
|
|
}
|
|
|
|
throw new Error(`Unexpected HeroSMS action: ${action} @ country ${country || 'n/a'}`);
|
|
},
|
|
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
|
|
getState: async () => ({ ...currentState }),
|
|
sendToContentScriptResilient: async (_source, message) => {
|
|
if (message.type === 'SUBMIT_PHONE_NUMBER') {
|
|
return {
|
|
phoneVerificationPage: true,
|
|
url: 'https://auth.openai.com/phone-verification',
|
|
};
|
|
}
|
|
if (message.type === 'RETURN_TO_ADD_PHONE') {
|
|
return {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
};
|
|
}
|
|
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
|
|
return {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
};
|
|
}
|
|
throw new Error(`Unexpected content-script message: ${message.type}`);
|
|
},
|
|
setState: async (updates) => {
|
|
currentState = { ...currentState, ...updates };
|
|
},
|
|
sleepWithStop: async () => {},
|
|
throwIfStopped: () => {},
|
|
});
|
|
|
|
const result = await helpers.completePhoneVerificationFlow(1, {
|
|
addPhonePage: true,
|
|
phoneVerificationPage: false,
|
|
url: 'https://auth.openai.com/add-phone',
|
|
});
|
|
|
|
assert.deepStrictEqual(result, {
|
|
success: true,
|
|
consentReady: true,
|
|
url: 'https://auth.openai.com/authorize',
|
|
});
|
|
|
|
const getNumberCountries = requests
|
|
.filter((requestUrl) => requestUrl.searchParams.get('action') === 'getNumber')
|
|
.map((requestUrl) => requestUrl.searchParams.get('country'));
|
|
assert.deepStrictEqual(getNumberCountries, ['52', '52', '16']);
|
|
});
|