Fix add-phone handoff and SMS Bower rotation
This commit is contained in:
@@ -208,9 +208,9 @@
|
|||||||
throw new Error(`步骤 ${completionStepForState(currentState)}:邮箱注册模式 OAuth 登录不应进入添加邮箱页。URL: ${result?.url || ''}`.trim());
|
throw new Error(`步骤 ${completionStepForState(currentState)}:邮箱注册模式 OAuth 登录不应进入添加邮箱页。URL: ${result?.url || ''}`.trim());
|
||||||
}
|
}
|
||||||
if (isStep7AddPhoneResult(result) || isStep7PhoneVerificationResult(result)) {
|
if (isStep7AddPhoneResult(result) || isStep7PhoneVerificationResult(result)) {
|
||||||
payload.skipLoginVerificationStep = true;
|
|
||||||
payload.addPhonePage = isStep7AddPhoneResult(result);
|
payload.addPhonePage = isStep7AddPhoneResult(result);
|
||||||
payload.phoneVerificationPage = isStep7PhoneVerificationResult(result);
|
payload.phoneVerificationPage = isStep7PhoneVerificationResult(result);
|
||||||
|
payload.directOAuthConsentPage = false;
|
||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
if (isStep7PlainVerificationResult(result)) {
|
if (isStep7PlainVerificationResult(result)) {
|
||||||
@@ -233,8 +233,8 @@
|
|||||||
}
|
}
|
||||||
await completeNodeFromBackground(state?.nodeId || 'oauth-login', {
|
await completeNodeFromBackground(state?.nodeId || 'oauth-login', {
|
||||||
loginVerificationRequestedAt: null,
|
loginVerificationRequestedAt: null,
|
||||||
skipLoginVerificationStep: true,
|
|
||||||
addPhonePage: true,
|
addPhonePage: true,
|
||||||
|
phoneVerificationPage: false,
|
||||||
directOAuthConsentPage: false,
|
directOAuthConsentPage: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,7 +365,11 @@
|
|||||||
await (String(options?.releaseAction || '').trim().toLowerCase() === 'ban'
|
await (String(options?.releaseAction || '').trim().toLowerCase() === 'ban'
|
||||||
? banActivation(state, activation, deps)
|
? banActivation(state, activation, deps)
|
||||||
: cancelActivation(state, activation, deps));
|
: cancelActivation(state, activation, deps));
|
||||||
return { currentTicketId: String(activation?.activationId || activation?.id || ''), nextActivation: null };
|
const nextActivation = await requestActivation(state, {
|
||||||
|
...options,
|
||||||
|
skipPreferredActivation: true,
|
||||||
|
}, deps);
|
||||||
|
return { currentTicketId: String(activation?.activationId || activation?.id || ''), nextActivation };
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractVerificationCode(raw = '') {
|
function extractVerificationCode(raw = '') {
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ test('step 7 preserves visible step when refreshing OAuth after retry', async ()
|
|||||||
assert.deepStrictEqual(events.refreshSteps, [9, 9, 9]);
|
assert.deepStrictEqual(events.refreshSteps, [9, 9, 9]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('step 7 hands add-phone to the dedicated post-login phone node without internal retry', async () => {
|
test('step 7 hands add-phone to the dedicated post-login phone node without internal retry and keeps login code node active', async () => {
|
||||||
const source = fs.readFileSync('flows/openai/background/steps/oauth-login.js', 'utf8');
|
const source = fs.readFileSync('flows/openai/background/steps/oauth-login.js', 'utf8');
|
||||||
const globalScope = {};
|
const globalScope = {};
|
||||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundStep7;`)(globalScope);
|
const api = new Function('self', `${source}; return self.MultiPageBackgroundStep7;`)(globalScope);
|
||||||
@@ -222,12 +222,16 @@ test('step 7 hands add-phone to the dedicated post-login phone node without inte
|
|||||||
step: 'oauth-login',
|
step: 'oauth-login',
|
||||||
payload: {
|
payload: {
|
||||||
loginVerificationRequestedAt: null,
|
loginVerificationRequestedAt: null,
|
||||||
skipLoginVerificationStep: true,
|
|
||||||
addPhonePage: true,
|
addPhonePage: true,
|
||||||
|
phoneVerificationPage: false,
|
||||||
directOAuthConsentPage: false,
|
directOAuthConsentPage: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
assert.ok(
|
||||||
|
!Object.prototype.hasOwnProperty.call(events.completions[0].payload, 'skipLoginVerificationStep'),
|
||||||
|
'add-phone handoff must keep the login-code node active so step 9 phone verification can run next'
|
||||||
|
);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
!events.logs.some(({ message }) => /准备重试/.test(message)),
|
!events.logs.some(({ message }) => /准备重试/.test(message)),
|
||||||
'add-phone failure should not be logged as an internal retryable attempt'
|
'add-phone failure should not be logged as an internal retryable attempt'
|
||||||
@@ -291,8 +295,8 @@ test('step 7 no longer runs shared phone verification inside oauth-login', async
|
|||||||
step: 'oauth-login',
|
step: 'oauth-login',
|
||||||
payload: {
|
payload: {
|
||||||
loginVerificationRequestedAt: null,
|
loginVerificationRequestedAt: null,
|
||||||
skipLoginVerificationStep: true,
|
|
||||||
addPhonePage: true,
|
addPhonePage: true,
|
||||||
|
phoneVerificationPage: false,
|
||||||
directOAuthConsentPage: false,
|
directOAuthConsentPage: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -142,3 +142,54 @@ test('SMS Bower provider acquires number with getNumberV2, polls code, and updat
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('SMS Bower rotate cancels rejected number then immediately acquires the next number', async () => {
|
||||||
|
const requests = [];
|
||||||
|
const provider = api.createProvider({
|
||||||
|
fetchImpl: async (url, options = {}) => {
|
||||||
|
const parsed = new URL(url);
|
||||||
|
const action = parsed.searchParams.get('action');
|
||||||
|
requests.push({ url: parsed, options });
|
||||||
|
if (action === 'setStatus') {
|
||||||
|
return createTextResponse('ACCESS_CANCEL');
|
||||||
|
}
|
||||||
|
if (action === 'getNumberV2') {
|
||||||
|
return createTextResponse({ activationId: 'next-activation', phoneNumber: '447700900456', activationCost: 0.22, countryCode: 16 });
|
||||||
|
}
|
||||||
|
throw new Error(`unexpected ${parsed.toString()}`);
|
||||||
|
},
|
||||||
|
sleepWithStop: async () => {},
|
||||||
|
throwIfStopped: () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
smsBowerApiKey: 'demo-key',
|
||||||
|
smsBowerServiceCode: 'dr',
|
||||||
|
smsBowerCountryId: 16,
|
||||||
|
smsBowerCountryLabel: 'United Kingdom',
|
||||||
|
smsBowerMinPrice: '0.1',
|
||||||
|
smsBowerMaxPrice: '0.3',
|
||||||
|
};
|
||||||
|
|
||||||
|
const rotated = await provider.rotateActivation(
|
||||||
|
state,
|
||||||
|
{ activationId: 'old-activation', phoneNumber: '447700900123', provider: 'sms-bower', countryId: 16 },
|
||||||
|
{ releaseAction: 'cancel', blockedCountryIds: [] }
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(rotated.currentTicketId, 'old-activation');
|
||||||
|
assert.equal(rotated.nextActivation.activationId, 'next-activation');
|
||||||
|
assert.equal(rotated.nextActivation.phoneNumber, '447700900456');
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
requests.map((entry) => [
|
||||||
|
entry.url.searchParams.get('action'),
|
||||||
|
entry.url.searchParams.get('id'),
|
||||||
|
entry.url.searchParams.get('status'),
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
['setStatus', 'old-activation', '8'],
|
||||||
|
['getNumberV2', null, null],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user