fix(auth): preserve phone identity when step payload carries bound email
This commit is contained in:
@@ -83,6 +83,65 @@ const defaultStepDefinitions = {
|
||||
10: { key: 'platform-verify' },
|
||||
};
|
||||
|
||||
const PHONE_IDENTITY_STATE_KEYS = [
|
||||
'phoneNumber',
|
||||
'signupPhoneNumber',
|
||||
'signupPhoneActivation',
|
||||
'signupPhoneCompletedActivation',
|
||||
'signupPhoneVerificationRequestedAt',
|
||||
'signupPhoneVerificationPurpose',
|
||||
'accountIdentifierType',
|
||||
'accountIdentifier',
|
||||
];
|
||||
|
||||
function createDownstreamResetHarness(stepKey = '') {
|
||||
return new Function(`
|
||||
function getStepExecutionKeyForState() {
|
||||
return ${JSON.stringify(stepKey)};
|
||||
}
|
||||
${extractFunction('getDownstreamStateResets')}
|
||||
return { getDownstreamStateResets };
|
||||
`)();
|
||||
}
|
||||
|
||||
test('downstream restarts after account creation preserve phone signup identity fields', () => {
|
||||
const numericResetHarness = createDownstreamResetHarness('');
|
||||
const stepKeyResetHarnesses = [
|
||||
createDownstreamResetHarness('oauth-login'),
|
||||
createDownstreamResetHarness('fetch-login-code'),
|
||||
createDownstreamResetHarness('confirm-oauth'),
|
||||
];
|
||||
const phoneState = {
|
||||
accountIdentifierType: 'phone',
|
||||
accountIdentifier: '+447780579093',
|
||||
signupPhoneNumber: '+447780579093',
|
||||
signupPhoneActivation: { activationId: 'active', phoneNumber: '+447780579093' },
|
||||
signupPhoneCompletedActivation: { activationId: 'done', phoneNumber: '+447780579093' },
|
||||
};
|
||||
|
||||
for (const step of [5, 6, 7, 8, 9]) {
|
||||
const resets = numericResetHarness.getDownstreamStateResets(step, phoneState);
|
||||
for (const key of PHONE_IDENTITY_STATE_KEYS) {
|
||||
assert.equal(
|
||||
Object.prototype.hasOwnProperty.call(resets, key),
|
||||
false,
|
||||
`step ${step} reset must not clear ${key}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const harness of stepKeyResetHarnesses) {
|
||||
const resets = harness.getDownstreamStateResets(10, phoneState);
|
||||
for (const key of PHONE_IDENTITY_STATE_KEYS) {
|
||||
assert.equal(
|
||||
Object.prototype.hasOwnProperty.call(resets, key),
|
||||
false,
|
||||
`${key} must not be cleared by step-key reset`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function createHarness(options = {}) {
|
||||
const {
|
||||
startStep = 7,
|
||||
|
||||
@@ -14,6 +14,7 @@ function createRouter(overrides = {}) {
|
||||
broadcasts: [],
|
||||
balanceRefreshes: [],
|
||||
emailStates: [],
|
||||
persistedRegistrationEmails: [],
|
||||
signupPhoneStates: [],
|
||||
signupPhoneSilentStates: [],
|
||||
finalizePayloads: [],
|
||||
@@ -123,6 +124,9 @@ function createRouter(overrides = {}) {
|
||||
events.emailStates.push(email);
|
||||
},
|
||||
setEmailStateSilently: async () => {},
|
||||
persistRegistrationEmailState: async (state, email, options) => {
|
||||
events.persistedRegistrationEmails.push({ state, email, options });
|
||||
},
|
||||
setSignupPhoneState: async (phoneNumber) => {
|
||||
events.signupPhoneStates.push(phoneNumber);
|
||||
},
|
||||
@@ -206,14 +210,38 @@ test('message router clears stale signup phone runtime when step 2 resolves emai
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(events.emailStates, ['user@example.com']);
|
||||
assert.deepStrictEqual(events.signupPhoneSilentStates, [null]);
|
||||
assert.ok(events.stateUpdates.some((updates) => (
|
||||
updates.accountIdentifierType === 'email'
|
||||
&& updates.accountIdentifier === 'user@example.com'
|
||||
&& updates.signupPhoneNumber === ''
|
||||
&& updates.signupPhoneActivation === null
|
||||
&& updates.signupPhoneCompletedActivation === null
|
||||
)));
|
||||
assert.deepStrictEqual(events.signupPhoneSilentStates, []);
|
||||
assert.deepStrictEqual(events.stateUpdates, []);
|
||||
});
|
||||
|
||||
test('message router preserves phone signup identity when step payload only reports registration email', async () => {
|
||||
const { router, events } = createRouter({
|
||||
state: {
|
||||
stepStatuses: { 3: 'pending' },
|
||||
accountIdentifierType: 'phone',
|
||||
accountIdentifier: '+66959916439',
|
||||
signupPhoneNumber: '+66959916439',
|
||||
signupPhoneActivation: { activationId: 'active', phoneNumber: '+66959916439' },
|
||||
},
|
||||
});
|
||||
|
||||
await router.handleStepData(3, {
|
||||
email: 'bound@example.com',
|
||||
signupVerificationRequestedAt: 123456,
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(events.emailStates, []);
|
||||
assert.equal(events.persistedRegistrationEmails.length, 1);
|
||||
assert.equal(events.persistedRegistrationEmails[0].email, 'bound@example.com');
|
||||
assert.deepStrictEqual(events.persistedRegistrationEmails[0].options, {
|
||||
source: 'step_identity',
|
||||
preserveAccountIdentity: true,
|
||||
});
|
||||
assert.equal(events.persistedRegistrationEmails[0].state.signupPhoneNumber, '+66959916439');
|
||||
assert.equal(events.persistedRegistrationEmails[0].state.accountIdentifierType, 'phone');
|
||||
assert.equal(events.signupPhoneSilentStates.length, 0);
|
||||
assert.ok(!events.stateUpdates.some((updates) => updates.signupPhoneNumber === ''));
|
||||
assert.ok(events.stateUpdates.some((updates) => updates.signupVerificationRequestedAt === 123456));
|
||||
});
|
||||
|
||||
test('message router does not overwrite a completed step 3 when step 2 is replayed', async () => {
|
||||
|
||||
Reference in New Issue
Block a user