fix(auth): prevent stale login attempts from replacing sessions (#663)

This commit is contained in:
InfinityPacer
2026-08-11 11:33:00 +08:00
committed by GitHub
parent bf0e57a92f
commit 202235d88a
5 changed files with 1175 additions and 40 deletions
@@ -9,11 +9,14 @@ vi.mock('vue-i18n', () => ({
const slotStub = { template: '<div><slot /></div>' }
const buttonStub = {
emits: ['click'],
props: ['loading'],
template: '<button :disabled="loading" @click="$emit(\'click\')"><slot /></button>',
props: ['disabled', 'loading', 'type'],
template: '<button :type="type" :disabled="loading || disabled" @click="$emit(\'click\')"><slot /></button>',
}
function mountStep(methods: Array<'otp'>) {
function mountStep(
methods: Array<'otp'>,
props: Partial<{ errorMessage: string; otpLoading: boolean; otpPassword: string }> = {},
) {
return shallowMount(LoginMfaStep, {
global: {
stubs: {
@@ -28,6 +31,7 @@ function mountStep(methods: Array<'otp'>) {
methods,
otpLoading: false,
otpPassword: '',
...props,
},
})
}
@@ -44,4 +48,44 @@ describe('LoginMfaStep', () => {
expect(wrapper.find('[data-testid="mfa-otp-form"]').exists()).toBe(false)
})
it('emits the OTP value and submits the current verification step', async () => {
const wrapper = mountStep(['otp'])
const input = wrapper.get('input[name="otp"]')
await input.setValue('123456')
await wrapper.setProps({ otpPassword: '123456' })
await wrapper.get('[data-testid="mfa-otp-form"]').trigger('submit')
expect(wrapper.emitted('update:otpPassword')).toEqual([['123456']])
expect(wrapper.emitted('otp')).toHaveLength(1)
})
it('disables submission until an OTP is present', () => {
const wrapper = mountStep(['otp'])
expect(wrapper.get('button[type="submit"]').attributes('disabled')).toBeDefined()
})
it('locks input, back and submit actions while OTP verification is pending', () => {
const wrapper = mountStep(['otp'], { otpLoading: true, otpPassword: '123456' })
expect(wrapper.get('input[name="otp"]').attributes('disabled')).toBeDefined()
expect(wrapper.get('[data-testid="mfa-back"]').attributes('disabled')).toBeDefined()
expect(wrapper.get('button[type="submit"]').attributes('disabled')).toBeDefined()
})
it('emits back when the user returns to password login', async () => {
const wrapper = mountStep(['otp'])
await wrapper.get('[data-testid="mfa-back"]').trigger('click')
expect(wrapper.emitted('back')).toHaveLength(1)
})
it('shows the current verification error', () => {
const wrapper = mountStep(['otp'], { errorMessage: '验证码错误' })
expect(wrapper.text()).toContain('验证码错误')
})
})