mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-11-08 00:54:17 +00:00
fix: tighten pending oauth email routing and binding state
This commit is contained in:
1 parent
dcd5c43da4
commit
7e89bca5e6
9 files changed
+685
-54
No files matched your search
@@ -8,6 +8,7 @@ const {
|
||||
showErrorMock,
|
||||
registerMock,
|
||||
setTokenMock,
|
||||
setPendingAuthSessionMock,
|
||||
clearPendingAuthSessionMock,
|
||||
getPublicSettingsMock,
|
||||
sendVerifyCodeMock,
|
||||
@@ -21,6 +22,7 @@ const {
|
||||
showErrorMock: vi.fn(),
|
||||
registerMock: vi.fn(),
|
||||
setTokenMock: vi.fn(),
|
||||
setPendingAuthSessionMock: vi.fn(),
|
||||
clearPendingAuthSessionMock: vi.fn(),
|
||||
getPublicSettingsMock: vi.fn(),
|
||||
sendVerifyCodeMock: vi.fn(),
|
||||
@@ -68,6 +70,7 @@ vi.mock('@/stores', () => ({
|
||||
pendingAuthSession: authStoreState.pendingAuthSession,
|
||||
register: (...args: any[]) => registerMock(...args),
|
||||
setToken: (...args: any[]) => setTokenMock(...args),
|
||||
setPendingAuthSession: (...args: any[]) => setPendingAuthSessionMock(...args),
|
||||
clearPendingAuthSession: (...args: any[]) => clearPendingAuthSessionMock(...args),
|
||||
}),
|
||||
useAppStore: () => ({
|
||||
@@ -100,6 +103,7 @@ describe('EmailVerifyView', () => {
|
||||
showErrorMock.mockReset()
|
||||
registerMock.mockReset()
|
||||
setTokenMock.mockReset()
|
||||
setPendingAuthSessionMock.mockReset()
|
||||
clearPendingAuthSessionMock.mockReset()
|
||||
getPublicSettingsMock.mockReset()
|
||||
sendVerifyCodeMock.mockReset()
|
||||
@@ -196,6 +200,97 @@ describe('EmailVerifyView', () => {
|
||||
expect(showErrorMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('uses the pending oauth verify-code endpoint when auth store only carries the pending provider', async () => {
|
||||
authStoreState.pendingAuthSession = {
|
||||
token: '',
|
||||
token_field: 'pending_oauth_token',
|
||||
provider: 'oidc',
|
||||
redirect: '/profile',
|
||||
}
|
||||
getPublicSettingsMock.mockResolvedValue({
|
||||
turnstile_enabled: false,
|
||||
turnstile_site_key: '',
|
||||
site_name: 'Sub2API',
|
||||
registration_email_suffix_whitelist: ['allowed.com'],
|
||||
})
|
||||
sessionStorage.setItem(
|
||||
'register_data',
|
||||
JSON.stringify({
|
||||
email: 'fresh@example.com',
|
||||
password: 'secret-123',
|
||||
})
|
||||
)
|
||||
|
||||
mount(EmailVerifyView, {
|
||||
global: {
|
||||
stubs: {
|
||||
AuthLayout: { template: '<div><slot /><slot name="footer" /></div>' },
|
||||
Icon: true,
|
||||
TurnstileWidget: true,
|
||||
transition: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
await flushPromises()
|
||||
|
||||
expect(sendPendingOAuthVerifyCodeMock).toHaveBeenCalledWith({
|
||||
email: 'fresh@example.com',
|
||||
pending_oauth_token: undefined,
|
||||
})
|
||||
expect(sendVerifyCodeMock).not.toHaveBeenCalled()
|
||||
expect(showErrorMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('returns to the oauth callback flow when pending send-code detects an existing account email', async () => {
|
||||
authStoreState.pendingAuthSession = {
|
||||
token: '',
|
||||
token_field: 'pending_oauth_token',
|
||||
provider: 'oidc',
|
||||
redirect: '/profile/security',
|
||||
}
|
||||
getPublicSettingsMock.mockResolvedValue({
|
||||
turnstile_enabled: false,
|
||||
turnstile_site_key: '',
|
||||
site_name: 'Sub2API',
|
||||
registration_email_suffix_whitelist: ['allowed.com'],
|
||||
})
|
||||
sendPendingOAuthVerifyCodeMock.mockResolvedValue({
|
||||
auth_result: 'pending_session',
|
||||
provider: 'oidc',
|
||||
redirect: '/profile/security',
|
||||
})
|
||||
sessionStorage.setItem(
|
||||
'register_data',
|
||||
JSON.stringify({
|
||||
email: 'fresh@example.com',
|
||||
password: 'secret-123',
|
||||
})
|
||||
)
|
||||
|
||||
mount(EmailVerifyView, {
|
||||
global: {
|
||||
stubs: {
|
||||
AuthLayout: { template: '<div><slot /><slot name="footer" /></div>' },
|
||||
Icon: true,
|
||||
TurnstileWidget: true,
|
||||
transition: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
await flushPromises()
|
||||
|
||||
expect(setPendingAuthSessionMock).toHaveBeenCalledWith({
|
||||
token: '',
|
||||
token_field: 'pending_oauth_token',
|
||||
provider: 'oidc',
|
||||
redirect: '/profile/security',
|
||||
})
|
||||
expect(pushMock).toHaveBeenCalledWith('/auth/oidc/callback')
|
||||
expect(showErrorMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('submits pending auth account creation when session storage has no pending metadata but auth store does', async () => {
|
||||
authStoreState.pendingAuthSession = {
|
||||
token: 'pending-token-1',
|
||||
@@ -252,6 +347,70 @@ describe('EmailVerifyView', () => {
|
||||
expect(registerMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('returns to the oauth callback flow when pending account creation becomes bind-login', async () => {
|
||||
authStoreState.pendingAuthSession = {
|
||||
token: '',
|
||||
token_field: 'pending_oauth_token',
|
||||
provider: 'oidc',
|
||||
redirect: '/profile/security',
|
||||
}
|
||||
getPublicSettingsMock.mockResolvedValue({
|
||||
turnstile_enabled: false,
|
||||
turnstile_site_key: '',
|
||||
site_name: 'Sub2API',
|
||||
registration_email_suffix_whitelist: ['allowed.com'],
|
||||
})
|
||||
sessionStorage.setItem(
|
||||
'register_data',
|
||||
JSON.stringify({
|
||||
email: 'fresh@example.com',
|
||||
password: 'secret-123',
|
||||
})
|
||||
)
|
||||
apiClientPostMock.mockResolvedValue({
|
||||
data: {
|
||||
auth_result: 'pending_session',
|
||||
provider: 'oidc',
|
||||
step: 'bind_login_required',
|
||||
redirect: '/profile/security',
|
||||
email: 'fresh@example.com',
|
||||
},
|
||||
})
|
||||
|
||||
const wrapper = mount(EmailVerifyView, {
|
||||
global: {
|
||||
stubs: {
|
||||
AuthLayout: { template: '<div><slot /><slot name="footer" /></div>' },
|
||||
Icon: true,
|
||||
TurnstileWidget: true,
|
||||
transition: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
await flushPromises()
|
||||
await wrapper.get('#code').setValue('123456')
|
||||
await wrapper.get('form').trigger('submit.prevent')
|
||||
await flushPromises()
|
||||
|
||||
expect(apiClientPostMock).toHaveBeenCalledWith('/auth/oauth/pending/create-account', {
|
||||
email: 'fresh@example.com',
|
||||
password: 'secret-123',
|
||||
verify_code: '123456',
|
||||
})
|
||||
expect(setPendingAuthSessionMock).toHaveBeenCalledWith({
|
||||
token: '',
|
||||
token_field: 'pending_oauth_token',
|
||||
provider: 'oidc',
|
||||
redirect: '/profile/security',
|
||||
})
|
||||
expect(pushMock).toHaveBeenCalledWith('/auth/oidc/callback')
|
||||
expect(setTokenMock).not.toHaveBeenCalled()
|
||||
expect(persistOAuthTokenContextMock).not.toHaveBeenCalled()
|
||||
expect(clearPendingAuthSessionMock).not.toHaveBeenCalled()
|
||||
expect(showSuccessMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('keeps the normal email registration flow unchanged', async () => {
|
||||
sessionStorage.setItem(
|
||||
'register_data',
|
||||
|
||||
Reference in new issue
Block a user