fix(auth): retain protected deep-link state through sign-in

This commit is contained in:
cesnimda
2026-10-10 14:32:24 +02:00
parent c37cab560a
commit 6843767176
6 changed files with 250 additions and 18 deletions
+5 -5
View File
@@ -145,11 +145,11 @@ describe('LoginPage', () => {
mockMsalLoginPopup.mockResolvedValueOnce({ idToken: 'synthetic-microsoft-token' });
mockedApi.post.mockResolvedValueOnce({ data: { authenticated: true, provider: 'microsoft' } } as any);
renderLoginPage('login', '/jobs');
renderLoginPage('login', '/jobs?status=Applied#rows');
await click(await screen.findByRole('button', { name: 'Continue with Microsoft' }));
await waitFor(() => expect(mockedApi.post).toHaveBeenCalledWith('/auth/microsoft/exchange', { token: 'synthetic-microsoft-token', rememberMe: true }));
await waitFor(() => expect(mockNavigate).toHaveBeenCalledWith('/jobs', { replace: true }));
await waitFor(() => expect(mockNavigate).toHaveBeenCalledWith('/jobs?status=Applied#rows', { replace: true }));
});
it('completes a Google credential return without account-linking copy', async () => {
@@ -231,7 +231,7 @@ describe('LoginPage', () => {
'https://evil.example/analytics', '//evil.example/analytics', '/\t/evil.example',
'/%2f%2fevil.example', '/%252f%252fevil.example', '/%5cevil.example',
'/analytics?months=%ZZ', '/jobs/../login', '/%6cogin', '/register',
'/analytics%0a', '/analytics?months=6\n',
'/analytics%0a', '/analytics?months=6\n', '/LOGIN', '/%4cOGIN',
])('uses the safe fallback for the untrusted return target %j', async (from) => {
mockedApi.post.mockResolvedValueOnce({ data: { authenticated: true, provider: 'local' } } as any);
renderLoginPage('login', from);
@@ -302,7 +302,7 @@ describe('LoginPage', () => {
});
mockedApi.get.mockResolvedValueOnce({ data: { roles: [], email: 'person@example.com', userName: 'person' } } as any);
renderLoginPage();
renderLoginPage('login', '/analytics?months=24#activity');
await screen.findByLabelText('Username or email');
await userEvent.type(screen.getByLabelText('Username or email'), 'person@example.com');
@@ -317,7 +317,7 @@ describe('LoginPage', () => {
await waitFor(() => expect(mockedApi.post).toHaveBeenCalledWith('/auth/2fa/challenge', { pendingToken: 'pending-abc', code: '123456', trustDevice: false }));
await waitFor(() => expect(mockedApi.get).toHaveBeenCalledWith('/auth/me'));
await waitFor(() => expect(mockNavigate).toHaveBeenCalledWith('/dashboard', { replace: true }));
await waitFor(() => expect(mockNavigate).toHaveBeenCalledWith('/analytics?months=24#activity', { replace: true }));
});
it('shows a clear message when the 2FA challenge is rate-limited', async () => {