import { LoginHandler } from '../../../../../../src/identity/interaction/email-password/handler/LoginHandler'; import type { AccountStore } from '../../../../../../src/identity/interaction/email-password/storage/AccountStore'; import type { Interaction, InteractionHandlerInput, } from '../../../../../../src/identity/interaction/InteractionHandler'; import { FoundHttpError } from '../../../../../../src/util/errors/FoundHttpError'; import { createPostJsonOperation } from './Util'; describe('A LoginHandler', (): void => { const webId = 'http://alice.test.com/card#me'; const email = 'alice@test.email'; let oidcInteraction: jest.Mocked; let input: Required; let accountStore: jest.Mocked; let handler: LoginHandler; beforeEach(async(): Promise => { oidcInteraction = { exp: 123456, save: jest.fn(), } as any; input = { oidcInteraction } as any; accountStore = { authenticate: jest.fn().mockResolvedValue(webId), getSettings: jest.fn().mockResolvedValue({ useIdp: true }), } as any; handler = new LoginHandler(accountStore); }); it('errors if no oidcInteraction is defined on POST requests.', async(): Promise => { const error = expect.objectContaining({ statusCode: 400, message: 'This action can only be performed as part of an OIDC authentication flow.', errorCode: 'E0002', }); await expect(handler.canHandle({ operation: createPostJsonOperation({}) })).rejects.toThrow(error); await expect(handler.canHandle({ operation: createPostJsonOperation({}), oidcInteraction })) .resolves.toBeUndefined(); }); it('errors on invalid emails.', async(): Promise => { input.operation = createPostJsonOperation({}); await expect(handler.handle(input)).rejects.toThrow('Email required'); input.operation = createPostJsonOperation({ email: [ 'a', 'b' ]}); await expect(handler.handle(input)).rejects.toThrow('Email required'); }); it('errors on invalid passwords.', async(): Promise => { input.operation = createPostJsonOperation({ email }); await expect(handler.handle(input)).rejects.toThrow('Password required'); input.operation = createPostJsonOperation({ email, password: [ 'a', 'b' ]}); await expect(handler.handle(input)).rejects.toThrow('Password required'); }); it('throws an error if there is a problem.', async(): Promise => { input.operation = createPostJsonOperation({ email, password: 'password!' }); accountStore.authenticate.mockRejectedValueOnce(new Error('auth failed!')); await expect(handler.handle(input)).rejects.toThrow('auth failed!'); }); it('throws an error if the account does not have the correct settings.', async(): Promise => { input.operation = createPostJsonOperation({ email, password: 'password!' }); accountStore.getSettings.mockResolvedValueOnce({ useIdp: false }); await expect(handler.handle(input)) .rejects.toThrow('This server is not an identity provider for this account.'); }); it('returns the generated redirect URL.', async(): Promise => { input.operation = createPostJsonOperation({ email, password: 'password!' }); await expect(handler.handle(input)).rejects.toThrow(FoundHttpError); expect(accountStore.authenticate).toHaveBeenCalledTimes(1); expect(accountStore.authenticate).toHaveBeenLastCalledWith(email, 'password!'); expect(oidcInteraction.save).toHaveBeenCalledTimes(1); expect(oidcInteraction.result).toEqual({ login: { accountId: webId, remember: false }}); }); });