fix: defer HeroSMS reuse confirmation until final cleanup
This commit is contained in:
+1
-1
@@ -6691,7 +6691,6 @@ async function handleStepData(step, payload) {
|
|||||||
excludeLocalhostCallbacks: true,
|
excludeLocalhostCallbacks: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
await finalizePhoneActivationAfterSuccessfulFlow(latestState);
|
|
||||||
await finalizeIcloudAliasAfterSuccessfulFlow(latestState);
|
await finalizeIcloudAliasAfterSuccessfulFlow(latestState);
|
||||||
const shouldClearCustomPoolEmail = String(latestState?.emailGenerator || '').trim().toLowerCase() === (
|
const shouldClearCustomPoolEmail = String(latestState?.emailGenerator || '').trim().toLowerCase() === (
|
||||||
typeof CUSTOM_EMAIL_POOL_GENERATOR === 'string'
|
typeof CUSTOM_EMAIL_POOL_GENERATOR === 'string'
|
||||||
@@ -6701,6 +6700,7 @@ async function handleStepData(step, payload) {
|
|||||||
if ((shouldUseCustomRegistrationEmail(latestState) || shouldClearCustomPoolEmail) && latestState.email) {
|
if ((shouldUseCustomRegistrationEmail(latestState) || shouldClearCustomPoolEmail) && latestState.email) {
|
||||||
await setEmailStateSilently(null);
|
await setEmailStateSilently(null);
|
||||||
}
|
}
|
||||||
|
await finalizePhoneActivationAfterSuccessfulFlow(latestState);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,10 +203,10 @@
|
|||||||
excludeLocalhostCallbacks: true,
|
excludeLocalhostCallbacks: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
await finalizeIcloudAliasAfterSuccessfulFlow(latestState);
|
||||||
if (typeof finalizePhoneActivationAfterSuccessfulFlow === 'function') {
|
if (typeof finalizePhoneActivationAfterSuccessfulFlow === 'function') {
|
||||||
await finalizePhoneActivationAfterSuccessfulFlow(latestState);
|
await finalizePhoneActivationAfterSuccessfulFlow(latestState);
|
||||||
}
|
}
|
||||||
await finalizeIcloudAliasAfterSuccessfulFlow(latestState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleStepData(step, payload) {
|
async function handleStepData(step, payload) {
|
||||||
|
|||||||
@@ -248,18 +248,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolvePhoneConfig(state = {}) {
|
function resolvePhoneConfig(state = {}, options = {}) {
|
||||||
const apiKey = normalizeApiKey(state.heroSmsApiKey);
|
const apiKey = normalizeApiKey(state.heroSmsApiKey);
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
throw new Error('HeroSMS API key is missing. Save it in the side panel before running the phone flow.');
|
throw new Error('HeroSMS API key is missing. Save it in the side panel before running the phone flow.');
|
||||||
}
|
}
|
||||||
|
const requireMaxPrice = Boolean(options.requireMaxPrice);
|
||||||
const maxPrice = normalizeManualHeroSmsMaxPrice(state.heroSmsMaxPrice);
|
const maxPrice = normalizeManualHeroSmsMaxPrice(state.heroSmsMaxPrice);
|
||||||
if (!maxPrice) {
|
if (requireMaxPrice && !maxPrice) {
|
||||||
throw new Error('HeroSMS maxPrice is missing. Fill it in below the country selector before running the phone flow.');
|
throw new Error('HeroSMS maxPrice is missing. Fill it in below the country selector before running the phone flow.');
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
apiKey,
|
apiKey,
|
||||||
maxPrice,
|
...(maxPrice ? { maxPrice } : {}),
|
||||||
baseUrl: normalizeUrl(state.heroSmsBaseUrl, DEFAULT_HERO_SMS_BASE_URL),
|
baseUrl: normalizeUrl(state.heroSmsBaseUrl, DEFAULT_HERO_SMS_BASE_URL),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -324,7 +325,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function requestPhoneActivation(state = {}) {
|
async function requestPhoneActivation(state = {}) {
|
||||||
const config = resolvePhoneConfig(state);
|
const config = resolvePhoneConfig(state, { requireMaxPrice: true });
|
||||||
const countryConfig = resolveCountryConfig(state);
|
const countryConfig = resolveCountryConfig(state);
|
||||||
const maxPrice = config.maxPrice;
|
const maxPrice = config.maxPrice;
|
||||||
const buildFallbackActivation = (requestAction) => ({
|
const buildFallbackActivation = (requestAction) => ({
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ function createRouter(overrides = {}) {
|
|||||||
finalizeStep3Completion: overrides.finalizeStep3Completion || (async (payload) => {
|
finalizeStep3Completion: overrides.finalizeStep3Completion || (async (payload) => {
|
||||||
events.finalizePayloads.push(payload);
|
events.finalizePayloads.push(payload);
|
||||||
}),
|
}),
|
||||||
finalizeIcloudAliasAfterSuccessfulFlow: async () => {},
|
finalizeIcloudAliasAfterSuccessfulFlow: overrides.finalizeIcloudAliasAfterSuccessfulFlow || (async () => {}),
|
||||||
findHotmailAccount: async () => null,
|
findHotmailAccount: async () => null,
|
||||||
flushCommand: async () => {},
|
flushCommand: async () => {},
|
||||||
getCurrentLuckmailPurchase: () => null,
|
getCurrentLuckmailPurchase: () => null,
|
||||||
@@ -294,6 +294,40 @@ test('message router finalizes pending phone activation on platform verify succe
|
|||||||
assert.deepStrictEqual(events.phoneFinalizations, [state]);
|
assert.deepStrictEqual(events.phoneFinalizations, [state]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('message router does not finalize pending phone activation when icloud finalization fails', async () => {
|
||||||
|
const state = {
|
||||||
|
stepStatuses: { 10: 'pending' },
|
||||||
|
reusablePhoneActivation: {
|
||||||
|
activationId: '123456',
|
||||||
|
phoneNumber: '66959916439',
|
||||||
|
successfulUses: 0,
|
||||||
|
maxUses: 3,
|
||||||
|
},
|
||||||
|
pendingPhoneActivationConfirmation: {
|
||||||
|
activationId: '123456',
|
||||||
|
phoneNumber: '66959916439',
|
||||||
|
successfulUses: 0,
|
||||||
|
maxUses: 3,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const { router, events } = createRouter({
|
||||||
|
state,
|
||||||
|
getStepDefinitionForState: (step) => ({ id: step, key: step === 10 ? 'platform-verify' : '' }),
|
||||||
|
finalizeIcloudAliasAfterSuccessfulFlow: async () => {
|
||||||
|
throw new Error('icloud finalize failed');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await assert.rejects(
|
||||||
|
() => router.handleStepData(10, {
|
||||||
|
localhostUrl: 'http://localhost:1455/auth/callback?code=ok',
|
||||||
|
}),
|
||||||
|
/icloud finalize failed/
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.deepStrictEqual(events.phoneFinalizations, []);
|
||||||
|
});
|
||||||
|
|
||||||
test('message router marks step 3 failed when post-submit finalize fails', async () => {
|
test('message router marks step 3 failed when post-submit finalize fails', async () => {
|
||||||
const { router, events } = createRouter({
|
const { router, events } = createRouter({
|
||||||
finalizeStep3Completion: async () => {
|
finalizeStep3Completion: async () => {
|
||||||
|
|||||||
@@ -95,6 +95,53 @@ test('phone verification helper requires manual HeroSMS maxPrice', async () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('phone verification helper still clears existing activation when maxPrice is missing', async () => {
|
||||||
|
const requests = [];
|
||||||
|
let currentState = {
|
||||||
|
heroSmsApiKey: 'demo-key',
|
||||||
|
heroSmsMaxPrice: '',
|
||||||
|
currentPhoneActivation: {
|
||||||
|
activationId: '123456',
|
||||||
|
phoneNumber: '66959916439',
|
||||||
|
successfulUses: 0,
|
||||||
|
maxUses: 3,
|
||||||
|
},
|
||||||
|
reusablePhoneActivation: null,
|
||||||
|
pendingPhoneActivationConfirmation: null,
|
||||||
|
};
|
||||||
|
const helpers = api.createPhoneVerificationHelpers({
|
||||||
|
addLog: async () => {},
|
||||||
|
ensureStep8SignupPageReady: async () => {},
|
||||||
|
fetchImpl: async (url) => {
|
||||||
|
const parsedUrl = new URL(url);
|
||||||
|
requests.push(parsedUrl);
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
text: async () => 'ACCESS_CANCEL',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
getState: async () => currentState,
|
||||||
|
sendToContentScriptResilient: async () => ({}),
|
||||||
|
setState: async (updates) => {
|
||||||
|
currentState = { ...currentState, ...updates };
|
||||||
|
},
|
||||||
|
sleepWithStop: async () => {},
|
||||||
|
throwIfStopped: () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
await assert.rejects(
|
||||||
|
() => helpers.completePhoneVerificationFlow(1, { addPhonePage: true }),
|
||||||
|
/HeroSMS maxPrice is missing/i
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(requests.length, 1);
|
||||||
|
assert.equal(requests[0].searchParams.get('action'), 'setStatus');
|
||||||
|
assert.equal(requests[0].searchParams.get('id'), '123456');
|
||||||
|
assert.equal(requests[0].searchParams.get('status'), '8');
|
||||||
|
assert.equal(requests[0].searchParams.has('maxPrice'), false);
|
||||||
|
assert.equal(currentState.currentPhoneActivation, null);
|
||||||
|
});
|
||||||
|
|
||||||
test('phone verification helper retries with HeroSMS getNumberV2 when getNumber reports NO_NUMBERS', async () => {
|
test('phone verification helper retries with HeroSMS getNumberV2 when getNumber reports NO_NUMBERS', async () => {
|
||||||
const requests = [];
|
const requests = [];
|
||||||
const helpers = api.createPhoneVerificationHelpers({
|
const helpers = api.createPhoneVerificationHelpers({
|
||||||
|
|||||||
Reference in New Issue
Block a user