diff --git a/background.js b/background.js
index b566f8d..0ecbd43 100644
--- a/background.js
+++ b/background.js
@@ -21,7 +21,6 @@ importScripts(
'gopay-utils.js',
'phone-sms/providers/hero-sms.js',
'phone-sms/providers/five-sim.js',
- 'phone-sms/providers/nexsms.js',
'phone-sms/providers/madao.js',
'phone-sms/providers/registry.js',
'background/phone-verification-flow.js',
diff --git a/background/phone-verification-flow.js b/background/phone-verification-flow.js
index de0923c..c67fc45 100644
--- a/background/phone-verification-flow.js
+++ b/background/phone-verification-flow.js
@@ -6963,8 +6963,8 @@
);
};
- const rotateCurrentActivation = async (activationCandidate, reason = '', releaseAction = 'cancel') => {
- const normalizedActivation = normalizeActivation(activationCandidate);
+ const rotateCurrentActivation = async (reason = '', releaseAction = 'cancel') => {
+ const normalizedActivation = normalizeActivation(activation);
if (!normalizedActivation || getActivationProviderId(normalizedActivation, state) !== PHONE_SMS_PROVIDER_MADAO) {
return { handled: false, nextActivation: null };
}
@@ -6984,6 +6984,9 @@
if (!nextActivation) {
return { handled: true, nextActivation: null };
}
+ activation = nextActivation;
+ shouldCancelActivation = true;
+ await persistCurrentActivation(nextActivation);
await addLog(
`步骤 9:MaDao 已通过路由替换切换到新号码 ${nextActivation.phoneNumber}。`,
'info'
@@ -7001,19 +7004,13 @@
`步骤 9:添加手机号失败后正在更换号码(${formatStep9Reason(failureReason)},${usedNumberReplacementAttempts}/${maxNumberReplacementAttempts})。`,
'warn'
);
- const failedActivation = activation;
- const rotated = shouldCancelActivation && failedActivation
+ const rotated = shouldCancelActivation && activation
? await rotateCurrentActivation(
- failedActivation,
failureCode || failureReason,
getPhoneReplacementReleaseAction(failureCode || failureReason)
)
: { handled: false, nextActivation: null };
if (rotated.nextActivation) {
- activation = normalizeActivation(rotated.nextActivation);
- shouldCancelActivation = true;
- await clearCurrentActivation();
- await persistCurrentActivation(activation);
preferReuseExistingActivationOnAddPhone = false;
addPhoneReentryWithSameActivation = 0;
pageState = {
@@ -7129,14 +7126,9 @@
);
}
const rotated = shouldCancelActivation && activation
- ? await rotateCurrentActivation(activation, 'returned_to_add_phone_loop', 'cancel')
+ ? await rotateCurrentActivation('returned_to_add_phone_loop', 'cancel')
: { handled: false, nextActivation: null };
- if (rotated.nextActivation) {
- activation = normalizeActivation(rotated.nextActivation);
- shouldCancelActivation = true;
- await clearCurrentActivation();
- await persistCurrentActivation(activation);
- } else {
+ if (!rotated.nextActivation) {
if (!rotated.handled && shouldCancelActivation && activation) {
await cancelPhoneActivation(state, activation);
}
@@ -7199,14 +7191,9 @@
);
}
const rotated = shouldCancelActivation && activation
- ? await rotateCurrentActivation(activation, 'phone_number_used', 'ban')
+ ? await rotateCurrentActivation('phone_number_used', 'ban')
: { handled: false, nextActivation: null };
- if (rotated.nextActivation) {
- activation = normalizeActivation(rotated.nextActivation);
- shouldCancelActivation = true;
- await clearCurrentActivation();
- await persistCurrentActivation(activation);
- } else {
+ if (!rotated.nextActivation) {
if (!rotated.handled && shouldCancelActivation && activation) {
await banPhoneActivation(state, activation);
}
@@ -7295,8 +7282,6 @@
let shouldReplaceNumber = false;
let replaceReason = '';
- let failedActivationForReplacement = null;
- let replacementPreparedInAdvance = false;
for (let attempt = 1; attempt <= DEFAULT_PHONE_SUBMIT_ATTEMPTS; attempt += 1) {
throwIfStopped();
@@ -7306,7 +7291,6 @@
await markPreferredActivationExhausted(codeResult.reason || 'sms_timeout');
shouldReplaceNumber = true;
replaceReason = codeResult.reason || 'sms_not_received';
- failedActivationForReplacement = activation;
break;
}
@@ -7342,7 +7326,6 @@
if (isPhoneNumberUsedError(invalidErrorText)) {
shouldReplaceNumber = true;
replaceReason = 'phone_number_used';
- failedActivationForReplacement = activation;
await discardPhoneActivationFromReuse(
`目标站拒绝该号码(${invalidErrorText})。`,
activation,
@@ -7353,19 +7336,13 @@
`自动白嫖复用号码 ${activation.phoneNumber} 被目标站拒绝。`
);
}
- if (shouldCancelActivation && activation) {
- const rotated = await rotateCurrentActivation(activation, 'phone_number_used', 'ban');
- if (rotated.nextActivation) {
- activation = normalizeActivation(rotated.nextActivation);
- shouldCancelActivation = true;
- replacementPreparedInAdvance = true;
- } else if (rotated.handled) {
- activation = null;
- shouldCancelActivation = false;
- } else {
- await banPhoneActivation(state, activation);
- shouldCancelActivation = false;
- }
+ if (
+ shouldCancelActivation
+ && activation
+ && getActivationProviderId(activation, state) !== PHONE_SMS_PROVIDER_MADAO
+ ) {
+ await banPhoneActivation(state, activation);
+ shouldCancelActivation = false;
}
await addLog(
`步骤 9:手机号被提示已使用(${invalidErrorText}),立即更换新号码。`,
@@ -7377,20 +7354,13 @@
if (attempt >= DEFAULT_PHONE_SUBMIT_ATTEMPTS) {
shouldReplaceNumber = true;
replaceReason = 'code_rejected';
- failedActivationForReplacement = activation;
- if (shouldCancelActivation && activation) {
- const rotated = await rotateCurrentActivation(activation, 'code_rejected', 'ban');
- if (rotated.nextActivation) {
- activation = normalizeActivation(rotated.nextActivation);
- shouldCancelActivation = true;
- replacementPreparedInAdvance = true;
- } else if (rotated.handled) {
- activation = null;
- shouldCancelActivation = false;
- } else {
- await banPhoneActivation(state, activation);
- shouldCancelActivation = false;
- }
+ if (
+ shouldCancelActivation
+ && activation
+ && getActivationProviderId(activation, state) !== PHONE_SMS_PROVIDER_MADAO
+ ) {
+ await banPhoneActivation(state, activation);
+ shouldCancelActivation = false;
}
await addLog(
`步骤 9:手机验证码连续 ${DEFAULT_PHONE_SUBMIT_ATTEMPTS} 次被拒(${invalidErrorText}),将更换号码。`,
@@ -7496,47 +7466,33 @@
throw buildPhoneReplacementLimitError(maxNumberReplacementAttempts, replaceReason || 'unknown');
}
- const failedActivation = failedActivationForReplacement || activation;
- const rotated = replacementPreparedInAdvance
- ? { handled: true, nextActivation: activation }
- : (
- shouldCancelActivation && failedActivation
- ? await rotateCurrentActivation(
- failedActivation,
- replaceReason || 'replace_number',
- getPhoneReplacementReleaseAction(replaceReason || 'replace_number')
- )
- : { handled: false, nextActivation: null }
- );
- if (shouldRetireFreeReusableActivationOnFailure(await getState(), failedActivation)) {
+ const rotated = shouldCancelActivation && activation
+ ? await rotateCurrentActivation(
+ replaceReason || 'replace_number',
+ getPhoneReplacementReleaseAction(replaceReason || 'replace_number')
+ )
+ : { handled: false, nextActivation: null };
+ if (shouldRetireFreeReusableActivationOnFailure(await getState(), activation)) {
await retireFreeReusableActivation(
- `自动白嫖复用号码 ${failedActivation.phoneNumber} 在失败后被更换。`
+ `自动白嫖复用号码 ${activation.phoneNumber} 在失败后被更换。`
);
}
- if (isPhoneNumberUsedFailureReason(replaceReason) && failedActivation) {
+ if (isPhoneNumberUsedFailureReason(replaceReason)) {
await discardPhoneActivationFromReuse(
`目标站拒绝该号码(${replaceReason})。`,
- failedActivation,
+ activation,
await getState()
);
}
- await clearCurrentActivation();
- if (rotated.nextActivation) {
- activation = normalizeActivation(rotated.nextActivation);
- shouldCancelActivation = Boolean(activation);
- if (activation) {
- await persistCurrentActivation(activation);
- }
- } else {
- if (!rotated.handled && shouldCancelActivation && failedActivation) {
- await cancelPhoneActivation(state, failedActivation);
+ if (!rotated.nextActivation) {
+ if (!rotated.handled && shouldCancelActivation && activation) {
+ await cancelPhoneActivation(state, activation);
}
+ await clearCurrentActivation();
activation = null;
shouldCancelActivation = false;
}
addPhoneReentryWithSameActivation = 0;
- failedActivationForReplacement = null;
- replacementPreparedInAdvance = false;
let returnResult = null;
try {
diff --git a/phone-sms/providers/nexsms.js b/phone-sms/providers/nexsms.js
deleted file mode 100644
index d3a189a..0000000
--- a/phone-sms/providers/nexsms.js
+++ /dev/null
@@ -1,265 +0,0 @@
-// phone-sms/providers/nexsms.js - NexSMS provider registry adapter
-(function attachNexSmsProvider(root, factory) {
- root.PhoneSmsNexSmsProvider = factory();
-})(typeof self !== 'undefined' ? self : globalThis, function createNexSmsProviderModule() {
- const PROVIDER_ID = 'nexsms';
- const DEFAULT_BASE_URL = 'https://api.nexsms.net';
- const DEFAULT_SERVICE_CODE = 'ot';
- const DEFAULT_SERVICE_LABEL = 'OpenAI';
- const DEFAULT_COUNTRY_ID = 1;
- const DEFAULT_COUNTRY_LABEL = 'Country #1';
- const DEFAULT_REQUEST_TIMEOUT_MS = 20000;
-
- function normalizeBaseUrl(value = '') {
- const trimmed = String(value || '').trim() || DEFAULT_BASE_URL;
- try {
- return new URL(trimmed).toString().replace(/\/+$/, '');
- } catch {
- return DEFAULT_BASE_URL;
- }
- }
-
- function normalizeText(value = '', fallback = '') {
- return String(value || '').trim() || fallback;
- }
-
- function normalizeNexSmsCountryId(value, fallback = DEFAULT_COUNTRY_ID) {
- const parsed = Math.floor(Number(value));
- if (Number.isFinite(parsed) && parsed >= 0) {
- return parsed;
- }
- const fallbackParsed = Math.floor(Number(fallback));
- if (Number.isFinite(fallbackParsed) && fallbackParsed >= 0) {
- return fallbackParsed;
- }
- return DEFAULT_COUNTRY_ID;
- }
-
- function normalizeNexSmsCountryLabel(value = '', fallback = DEFAULT_COUNTRY_LABEL) {
- return normalizeText(value, fallback);
- }
-
- function normalizeNexSmsServiceCode(value = '', fallback = DEFAULT_SERVICE_CODE) {
- const normalized = String(value || '').trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '');
- if (normalized) {
- return normalized;
- }
- const fallbackNormalized = String(fallback || '').trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '');
- return fallbackNormalized || DEFAULT_SERVICE_CODE;
- }
-
- function normalizeNexSmsCountryOrder(value = []) {
- const source = Array.isArray(value)
- ? value
- : String(value || '')
- .split(/[\r\n,,;;]+/)
- .map((entry) => String(entry || '').trim())
- .filter(Boolean);
- const normalized = [];
- const seen = new Set();
-
- source.forEach((entry) => {
- let id = -1;
- let label = '';
- if (entry && typeof entry === 'object' && !Array.isArray(entry)) {
- id = normalizeNexSmsCountryId(entry.id ?? entry.countryId, -1);
- label = normalizeText(entry.label ?? entry.countryLabel, '');
- } else {
- const text = String(entry || '').trim();
- const structured = text.match(/^(\d+)\s*(?:[:|/-]\s*(.+))?$/);
- id = normalizeNexSmsCountryId(structured?.[1] || text, -1);
- label = normalizeText(structured?.[2], '');
- }
- if (id < 0 || seen.has(id)) {
- return;
- }
- seen.add(id);
- normalized.push({
- id,
- label: label || `Country #${id}`,
- });
- });
-
- return normalized.slice(0, 20);
- }
-
- function resolveCountryCandidates(state = {}) {
- const candidates = normalizeNexSmsCountryOrder(state?.nexSmsCountryOrder);
- if (candidates.length) {
- return candidates;
- }
- return [{
- id: normalizeNexSmsCountryId(state?.nexSmsCountryId, DEFAULT_COUNTRY_ID),
- label: normalizeNexSmsCountryLabel(state?.nexSmsCountryLabel, DEFAULT_COUNTRY_LABEL),
- }];
- }
-
- function parsePayload(text) {
- const trimmed = String(text || '').trim();
- if (!trimmed) {
- return '';
- }
- try {
- return JSON.parse(trimmed);
- } catch {
- return trimmed;
- }
- }
-
- function describePayload(raw) {
- if (typeof raw === 'string') {
- return raw.trim();
- }
- if (raw && typeof raw === 'object') {
- const message = normalizeText(raw.message || raw.error || raw.msg || raw.statusText, '');
- if (message) {
- return message;
- }
- try {
- return JSON.stringify(raw);
- } catch {
- return String(raw);
- }
- }
- return String(raw || '').trim();
- }
-
- function isSuccessPayload(payload) {
- return Boolean(payload && typeof payload === 'object' && !Array.isArray(payload) && Number(payload.code) === 0);
- }
-
- function resolveConfig(state = {}, deps = {}) {
- return {
- apiKey: normalizeText(state?.nexSmsApiKey),
- baseUrl: normalizeBaseUrl(state?.nexSmsBaseUrl || DEFAULT_BASE_URL),
- serviceCode: normalizeNexSmsServiceCode(state?.nexSmsServiceCode, DEFAULT_SERVICE_CODE),
- fetchImpl: deps.fetchImpl || (typeof fetch === 'function' ? fetch.bind(globalThis) : null),
- requestTimeoutMs: deps.requestTimeoutMs || DEFAULT_REQUEST_TIMEOUT_MS,
- };
- }
-
- async function fetchPayload(config, path, actionLabel, options = {}) {
- if (!config.fetchImpl) {
- throw new Error('NexSMS 网络请求实现不可用。');
- }
- if (!config.apiKey) {
- throw new Error('NexSMS API Key 缺失,请先在侧边栏保存接码 API Key。');
- }
- const controller = typeof AbortController === 'function' ? new AbortController() : null;
- const timeoutId = controller
- ? setTimeout(() => controller.abort(), Number(config.requestTimeoutMs) || DEFAULT_REQUEST_TIMEOUT_MS)
- : null;
-
- try {
- const method = String(options.method || 'GET').trim().toUpperCase() || 'GET';
- const requestUrl = new URL(path.replace(/^\/+/, ''), `${config.baseUrl.replace(/\/+$/, '')}/`);
- requestUrl.searchParams.set('apiKey', config.apiKey);
- Object.entries(options.query || {}).forEach(([key, value]) => {
- if (value === undefined || value === null || value === '') {
- return;
- }
- requestUrl.searchParams.set(key, String(value));
- });
- const headers = {
- Accept: 'application/json',
- ...(options.headers && typeof options.headers === 'object' ? options.headers : {}),
- };
- const requestInit = {
- method,
- headers,
- signal: controller?.signal,
- };
- if (method !== 'GET' && method !== 'HEAD' && options.body !== undefined) {
- requestInit.body = typeof options.body === 'string'
- ? options.body
- : JSON.stringify(options.body);
- if (!requestInit.headers['Content-Type']) {
- requestInit.headers['Content-Type'] = 'application/json';
- }
- }
- const response = await config.fetchImpl(requestUrl.toString(), requestInit);
- const text = await response.text();
- const payload = parsePayload(text);
- if (!response.ok) {
- const error = new Error(`${actionLabel}失败:${describePayload(payload) || response.status}`);
- error.payload = payload;
- error.status = response.status;
- throw error;
- }
- return payload;
- } catch (error) {
- if (error?.name === 'AbortError') {
- throw new Error(`${actionLabel}超时。`);
- }
- throw error;
- } finally {
- if (timeoutId) {
- clearTimeout(timeoutId);
- }
- }
- }
-
- async function fetchBalance(state = {}, deps = {}) {
- const config = resolveConfig(state, deps);
- const payload = await fetchPayload(config, '/api/user/getBalance', 'NexSMS get balance');
- if (!isSuccessPayload(payload)) {
- throw new Error(`NexSMS get balance 失败:${describePayload(payload) || 'empty response'}`);
- }
- const balance = Number(payload?.data?.balance);
- return {
- balance: Number.isFinite(balance) ? balance : null,
- raw: payload,
- };
- }
-
- async function fetchPrices(state = {}, countryConfig = {}, deps = {}) {
- const config = resolveConfig(state, deps);
- const countryId = normalizeNexSmsCountryId(countryConfig?.id, DEFAULT_COUNTRY_ID);
- return fetchPayload(config, '/api/getCountryByService', 'NexSMS getCountryByService', {
- query: {
- serviceCode: config.serviceCode,
- countryId,
- },
- });
- }
-
- function createProvider(deps = {}) {
- const providerDeps = {
- fetchImpl: deps.fetchImpl,
- requestTimeoutMs: deps.requestTimeoutMs || DEFAULT_REQUEST_TIMEOUT_MS,
- };
- return {
- id: PROVIDER_ID,
- label: 'NexSMS',
- defaultCountryId: DEFAULT_COUNTRY_ID,
- defaultCountryLabel: DEFAULT_COUNTRY_LABEL,
- defaultProduct: DEFAULT_SERVICE_LABEL,
- defaultServiceCode: DEFAULT_SERVICE_CODE,
- normalizeCountryId: normalizeNexSmsCountryId,
- normalizeCountryLabel: normalizeNexSmsCountryLabel,
- normalizeCountryOrder: normalizeNexSmsCountryOrder,
- normalizeServiceCode: normalizeNexSmsServiceCode,
- resolveCountryCandidates,
- fetchBalance: (state) => fetchBalance(state, providerDeps),
- fetchPrices: (state, countryConfig) => fetchPrices(state, countryConfig, providerDeps),
- describePayload,
- isSuccessPayload,
- };
- }
-
- return {
- PROVIDER_ID,
- DEFAULT_BASE_URL,
- DEFAULT_COUNTRY_ID,
- DEFAULT_COUNTRY_LABEL,
- DEFAULT_SERVICE_CODE,
- DEFAULT_SERVICE_LABEL,
- createProvider,
- describePayload,
- isSuccessPayload,
- normalizeNexSmsCountryId,
- normalizeNexSmsCountryLabel,
- normalizeNexSmsCountryOrder,
- normalizeNexSmsServiceCode,
- };
-});
diff --git a/sidepanel/sidepanel.html b/sidepanel/sidepanel.html
index 13855ad..19809da 100644
--- a/sidepanel/sidepanel.html
+++ b/sidepanel/sidepanel.html
@@ -1896,7 +1896,6 @@
-
diff --git a/tests/phone-sms-provider-registry.test.js b/tests/phone-sms-provider-registry.test.js
index 18666b0..9b4d61a 100644
--- a/tests/phone-sms-provider-registry.test.js
+++ b/tests/phone-sms-provider-registry.test.js
@@ -3,7 +3,6 @@ const assert = require('node:assert/strict');
const fs = require('node:fs');
const source = fs.readFileSync('phone-sms/providers/registry.js', 'utf8');
-const nexSmsSource = fs.readFileSync('phone-sms/providers/nexsms.js', 'utf8');
function loadRegistry(root = {}) {
return new Function('self', `${source}; return self.PhoneSmsProviderRegistry;`)(root);
@@ -17,9 +16,6 @@ test('phone sms provider registry normalizes ids, order and labels consistently'
PhoneSmsFiveSimProvider: {
createProvider: (deps = {}) => ({ provider: '5sim', deps }),
},
- PhoneSmsNexSmsProvider: {
- createProvider: (deps = {}) => ({ provider: 'nexsms', deps }),
- },
PhoneSmsMaDaoProvider: {
createProvider: (deps = {}) => ({ provider: 'madao', deps }),
},
@@ -56,29 +52,5 @@ test('phone sms provider registry normalizes ids, order and labels consistently'
registry.createProvider('madao', { foo: 2 }),
{ provider: 'madao', deps: { foo: 2 } }
);
- assert.deepStrictEqual(
- registry.createProvider('nexsms', { foo: 3 }),
- { provider: 'nexsms', deps: { foo: 3 } }
- );
-});
-
-test('phone sms provider registry creates the real NexSMS provider module', () => {
- const root = {};
- const nexSmsModule = new Function('self', `${nexSmsSource}; return self.PhoneSmsNexSmsProvider;`)(root);
- const registry = loadRegistry({
- PhoneSmsNexSmsProvider: nexSmsModule,
- });
-
- const provider = registry.createProvider('nexsms', { fetchImpl: async () => ({ ok: true, text: async () => '{}' }) });
-
- assert.equal(provider.id, 'nexsms');
- assert.equal(provider.label, 'NexSMS');
- assert.equal(provider.defaultServiceCode, 'ot');
- assert.deepStrictEqual(
- provider.normalizeCountryOrder(['1:Thailand', { id: 2, label: 'United States' }, '1:Duplicate']),
- [
- { id: 1, label: 'Thailand' },
- { id: 2, label: 'United States' },
- ]
- );
+ assert.throws(() => registry.createProvider('nexsms'), /接码平台模块未加载:nexsms/);
});
diff --git a/tests/phone-verification-flow.test.js b/tests/phone-verification-flow.test.js
index f2e6852..4682467 100644
--- a/tests/phone-verification-flow.test.js
+++ b/tests/phone-verification-flow.test.js
@@ -8955,148 +8955,6 @@ test('phone verification helper uses MaDao routing replace when add-phone reject
assert.equal(currentState.currentPhoneActivation, null);
});
-test('phone verification helper keeps failed MaDao activation separate after routing replace on invalid code', async () => {
- const requests = [];
- const submittedPhones = [];
- const removedReusePhones = [];
- let verificationSubmitCount = 0;
- let currentState = {
- phoneSmsProvider: 'madao',
- madaoBaseUrl: 'http://127.0.0.1:7822',
- madaoMode: 'routing_plan',
- madaoRoutingPlanId: 'rp-openai',
- verificationResendCount: 0,
- phoneVerificationReplacementLimit: 2,
- phoneCodeWaitSeconds: 15,
- phoneCodeTimeoutWindows: 1,
- phoneCodePollIntervalSeconds: 1,
- phoneCodePollMaxRounds: 1,
- currentPhoneActivation: null,
- reusablePhoneActivation: null,
- };
- const helpers = api.createPhoneVerificationHelpers({
- addLog: async () => {},
- createMaDaoProvider: maDaoModule.createProvider,
- ensureStep8SignupPageReady: async () => {},
- fetchImpl: async (url, options = {}) => {
- const parsedUrl = new URL(url);
- requests.push({ url: parsedUrl, body: options.body ? JSON.parse(options.body) : null });
- if (parsedUrl.pathname === '/api/acquire') {
- return {
- ok: true,
- status: 200,
- text: async () => JSON.stringify({
- ticket_id: 'madao-old',
- phone_number: '+441111111111',
- service: 'openai',
- country: 'GB',
- routing_plan_id: 'rp-openai',
- routing_item_id: 'route-old',
- status: 'waiting_code',
- }),
- };
- }
- if (parsedUrl.pathname === '/api/routing/replace') {
- return {
- ok: true,
- status: 200,
- text: async () => JSON.stringify({
- current_ticket_id: 'madao-old',
- current_ticket_release: { ticket_id: 'madao-old', status: 'banned' },
- next_ticket: {
- ticket_id: 'madao-new',
- phone_number: '+442222222222',
- service: 'openai',
- country: 'GB',
- routing_plan_id: 'rp-openai',
- routing_item_id: 'route-new',
- status: 'waiting_code',
- },
- }),
- };
- }
- if (parsedUrl.pathname === '/api/poll') {
- return {
- ok: true,
- status: 200,
- text: async () => JSON.stringify({
- ticket_id: parsedUrl.pathname,
- status: 'code_received',
- code: requests.filter((entry) => entry.url.pathname === '/api/poll').length === 1 ? '111111' : '222222',
- }),
- };
- }
- if (parsedUrl.pathname === '/api/release') {
- return {
- ok: true,
- status: 200,
- text: async () => JSON.stringify({ ok: true }),
- };
- }
- throw new Error(`Unexpected MaDao path: ${parsedUrl.pathname}`);
- },
- getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
- getState: async () => ({ ...currentState }),
- sendToContentScriptResilient: async (_source, message) => {
- if (message.type === 'SUBMIT_PHONE_NUMBER') {
- submittedPhones.push(message.payload.phoneNumber);
- return { phoneVerificationPage: true, url: 'https://auth.openai.com/phone-verification' };
- }
- if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
- verificationSubmitCount += 1;
- if (verificationSubmitCount === 1) {
- return {
- invalidCode: true,
- errorText: 'This phone number is already linked to another account',
- phoneVerificationPage: true,
- url: 'https://auth.openai.com/phone-verification',
- };
- }
- assert.equal(message.payload.code, '222222');
- return { success: true, consentReady: true, url: 'https://auth.openai.com/authorize' };
- }
- if (message.type === 'RETURN_TO_ADD_PHONE' || message.type === 'STEP8_GET_STATE') {
- return { addPhonePage: true, phoneVerificationPage: false, url: 'https://auth.openai.com/add-phone' };
- }
- throw new Error(`Unexpected content-script message: ${message.type}`);
- },
- setState: async (updates) => {
- if (Array.isArray(updates.reusablePhoneActivationPool)) {
- updates.reusablePhoneActivationPool.forEach((entry) => removedReusePhones.push(entry.phoneNumber));
- }
- 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(submittedPhones, ['+441111111111', '+442222222222']);
- assert.deepStrictEqual(
- requests.map((entry) => entry.url.pathname),
- ['/api/acquire', '/api/poll', '/api/routing/replace', '/api/poll', '/api/release']
- );
- assert.deepStrictEqual(requests[2].body, {
- ticket_id: 'madao-old',
- release_action: 'ban',
- failed_item_id: 'route-old',
- reason: 'phone_number_used',
- });
- assert.deepStrictEqual(requests[4].body, { ticket_id: 'madao-new', action: 'finish' });
- assert.equal(currentState.currentPhoneActivation, null);
- assert.equal(removedReusePhones.includes('+442222222222'), false);
-});
-
test('phone verification helper reacquires MaDao direct numbers after releasing rejected number', async () => {
const requests = [];
const submittedPhones = [];
diff --git a/tests/sidepanel-phone-verification-settings.test.js b/tests/sidepanel-phone-verification-settings.test.js
index a042622..814e0d4 100644
--- a/tests/sidepanel-phone-verification-settings.test.js
+++ b/tests/sidepanel-phone-verification-settings.test.js
@@ -88,7 +88,6 @@ test('sidepanel html exposes phone verification toggle and multi-provider SMS ro
assert.match(html, /id="select-phone-sms-provider"/);
assert.match(html, /\.\.\/phone-sms\/providers\/hero-sms\.js/);
assert.match(html, /\.\.\/phone-sms\/providers\/five-sim\.js/);
- assert.match(html, /\.\.\/phone-sms\/providers\/nexsms\.js/);
assert.match(html, /\.\.\/phone-sms\/providers\/madao\.js/);
assert.match(html, /\.\.\/phone-sms\/providers\/registry\.js/);
assert.match(html, /