91 lines
2.3 KiB
TypeScript
91 lines
2.3 KiB
TypeScript
import { act } from 'react';
|
|
import { createRoot, type Root } from 'react-dom/client';
|
|
import { createMemoryRouter, RouterProvider } from 'react-router-dom';
|
|
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
const { apiMock, oauth2Mock } = vi.hoisted(() => ({
|
|
apiMock: vi.fn(),
|
|
oauth2Mock: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('@/lib/api', () => ({
|
|
api: apiMock,
|
|
}));
|
|
|
|
vi.mock('@/lib/auth-client', () => ({
|
|
signIn: { oauth2: oauth2Mock },
|
|
}));
|
|
|
|
import { SsoCallbackPage } from './sso-callback';
|
|
|
|
const mountedRoots: Root[] = [];
|
|
|
|
beforeAll(() => {
|
|
Object.defineProperty(globalThis, 'IS_REACT_ACT_ENVIRONMENT', {
|
|
configurable: true,
|
|
value: true,
|
|
});
|
|
});
|
|
|
|
beforeEach(() => {
|
|
apiMock.mockResolvedValue([
|
|
{
|
|
id: 'authentik',
|
|
name: 'Authentik',
|
|
protocols: ['oidc'],
|
|
configured: true,
|
|
loginMode: 'oidc',
|
|
callbackPath: '/api/auth/oauth2/callback/authentik',
|
|
teamSync: { enabled: false, claim: null },
|
|
samlFallback: { configured: false, loginUrl: null },
|
|
warnings: [],
|
|
},
|
|
]);
|
|
oauth2Mock.mockResolvedValue({ data: null, error: null });
|
|
});
|
|
|
|
afterEach(async () => {
|
|
for (const root of mountedRoots.splice(0)) {
|
|
await act(async () => {
|
|
root.unmount();
|
|
});
|
|
}
|
|
document.body.replaceChildren();
|
|
apiMock.mockReset();
|
|
oauth2Mock.mockReset();
|
|
});
|
|
|
|
afterAll(() => {
|
|
Reflect.deleteProperty(globalThis, 'IS_REACT_ACT_ENVIRONMENT');
|
|
});
|
|
|
|
describe('SsoCallbackPage', () => {
|
|
it('rejects a control-character callback that normalizes to an external origin', async () => {
|
|
const router = createMemoryRouter(
|
|
[
|
|
{
|
|
path: '/auth/provider/:provider',
|
|
element: <SsoCallbackPage />,
|
|
},
|
|
],
|
|
{
|
|
initialEntries: ['/auth/provider/authentik?callbackURL=%2F%0A%2F%2Fevil.example'],
|
|
},
|
|
);
|
|
const container = document.createElement('div');
|
|
document.body.append(container);
|
|
const root = createRoot(container);
|
|
mountedRoots.push(root);
|
|
|
|
await act(async () => {
|
|
root.render(<RouterProvider router={router} />);
|
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
});
|
|
|
|
expect(oauth2Mock).toHaveBeenCalledWith({
|
|
providerId: 'authentik',
|
|
callbackURL: '/chat',
|
|
});
|
|
});
|
|
});
|