mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Pass optional Interaction to InteractionHandlers
This commit is contained in:
@@ -93,7 +93,7 @@ describe('An IdentityProviderHttpHandler', (): void => {
|
||||
request.method = 'POST';
|
||||
await expect(handler.handle({ request, response })).resolves.toBeUndefined();
|
||||
expect(routes.response.handler.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(routes.response.handler.handleSafe).toHaveBeenLastCalledWith({ request, response });
|
||||
expect(routes.response.handler.handleSafe).toHaveBeenLastCalledWith({ request });
|
||||
expect(templateHandler.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(templateHandler.handleSafe).toHaveBeenLastCalledWith(
|
||||
{ response, templateFile: routes.response.responseTemplate, contents: { key: 'val' }},
|
||||
@@ -106,7 +106,7 @@ describe('An IdentityProviderHttpHandler', (): void => {
|
||||
(routes.response.handler as jest.Mocked<InteractionHandler>).handleSafe.mockResolvedValueOnce({ type: 'response' });
|
||||
await expect(handler.handle({ request, response })).resolves.toBeUndefined();
|
||||
expect(routes.response.handler.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(routes.response.handler.handleSafe).toHaveBeenLastCalledWith({ request, response });
|
||||
expect(routes.response.handler.handleSafe).toHaveBeenLastCalledWith({ request });
|
||||
expect(templateHandler.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(templateHandler.handleSafe).toHaveBeenLastCalledWith(
|
||||
{ response, templateFile: routes.response.responseTemplate, contents: {}},
|
||||
@@ -118,7 +118,7 @@ describe('An IdentityProviderHttpHandler', (): void => {
|
||||
request.method = 'POST';
|
||||
await expect(handler.handle({ request, response })).resolves.toBeUndefined();
|
||||
expect(routes.complete.handler.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(routes.complete.handler.handleSafe).toHaveBeenLastCalledWith({ request, response });
|
||||
expect(routes.complete.handler.handleSafe).toHaveBeenLastCalledWith({ request });
|
||||
expect(interactionCompleter.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(interactionCompleter.handleSafe).toHaveBeenLastCalledWith({ request, response, webId: 'webId' });
|
||||
});
|
||||
@@ -126,18 +126,22 @@ describe('An IdentityProviderHttpHandler', (): void => {
|
||||
it('matches paths based on prompt for requests to the root IDP.', async(): Promise<void> => {
|
||||
request.url = '/idp';
|
||||
request.method = 'POST';
|
||||
provider.interactionDetails.mockResolvedValueOnce({ prompt: { name: 'other' }} as any);
|
||||
const oidcInteraction = { prompt: { name: 'other' }};
|
||||
provider.interactionDetails.mockResolvedValueOnce(oidcInteraction as any);
|
||||
await expect(handler.handle({ request, response })).resolves.toBeUndefined();
|
||||
expect(routes.response.handler.handleSafe).toHaveBeenCalledTimes(0);
|
||||
expect(routes.complete.handler.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(routes.complete.handler.handleSafe).toHaveBeenLastCalledWith({ request, oidcInteraction });
|
||||
});
|
||||
|
||||
it('uses the default route for requests to the root IDP without (matching) prompt.', async(): Promise<void> => {
|
||||
request.url = '/idp';
|
||||
request.method = 'POST';
|
||||
provider.interactionDetails.mockResolvedValueOnce({ prompt: { name: 'notSupported' }} as any);
|
||||
const oidcInteraction = { prompt: { name: 'notSupported' }};
|
||||
provider.interactionDetails.mockResolvedValueOnce(oidcInteraction as any);
|
||||
await expect(handler.handle({ request, response })).resolves.toBeUndefined();
|
||||
expect(routes.response.handler.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(routes.response.handler.handleSafe).toHaveBeenLastCalledWith({ request, oidcInteraction });
|
||||
expect(routes.complete.handler.handleSafe).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,45 +1,31 @@
|
||||
import type { Provider } from 'oidc-provider';
|
||||
import type { ProviderFactory } from '../../../../src/identity/configuration/ProviderFactory';
|
||||
import type { Interaction } from '../../../../src/identity/interaction/email-password/handler/InteractionHandler';
|
||||
import { SessionHttpHandler } from '../../../../src/identity/interaction/SessionHttpHandler';
|
||||
import type { HttpRequest } from '../../../../src/server/HttpRequest';
|
||||
import type { HttpResponse } from '../../../../src/server/HttpResponse';
|
||||
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
|
||||
|
||||
describe('A SessionHttpHandler', (): void => {
|
||||
const request: HttpRequest = {} as any;
|
||||
const response: HttpResponse = {} as any;
|
||||
const webId = 'http://test.com/id#me';
|
||||
let details: any = {};
|
||||
let provider: Provider;
|
||||
let oidcInteraction: Interaction;
|
||||
let handler: SessionHttpHandler;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
details = { session: { accountId: webId }};
|
||||
provider = {
|
||||
interactionDetails: jest.fn().mockResolvedValue(details),
|
||||
} as any;
|
||||
oidcInteraction = { session: { accountId: webId }} as any;
|
||||
|
||||
const factory: ProviderFactory = {
|
||||
getProvider: jest.fn().mockResolvedValue(provider),
|
||||
};
|
||||
|
||||
handler = new SessionHttpHandler(factory);
|
||||
handler = new SessionHttpHandler();
|
||||
});
|
||||
|
||||
it('requires a session and accountId.', async(): Promise<void> => {
|
||||
details.session = undefined;
|
||||
await expect(handler.handle({ request, response })).rejects.toThrow(NotImplementedHttpError);
|
||||
it('requires a defined oidcInteraction with a session.', async(): Promise<void> => {
|
||||
oidcInteraction!.session = undefined;
|
||||
await expect(handler.handle({ request, oidcInteraction })).rejects.toThrow(NotImplementedHttpError);
|
||||
|
||||
details.session = { accountId: undefined };
|
||||
await expect(handler.handle({ request, response })).rejects.toThrow(NotImplementedHttpError);
|
||||
await expect(handler.handle({ request })).rejects.toThrow(NotImplementedHttpError);
|
||||
});
|
||||
|
||||
it('calls the oidc completer with the webId in the session.', async(): Promise<void> => {
|
||||
await expect(handler.handle({ request, response })).resolves.toEqual({
|
||||
it('returns an InteractionCompleteResult when done.', async(): Promise<void> => {
|
||||
await expect(handler.handle({ request, oidcInteraction })).resolves.toEqual({
|
||||
details: { webId },
|
||||
type: 'complete',
|
||||
});
|
||||
expect(provider.interactionDetails).toHaveBeenCalledTimes(1);
|
||||
expect(provider.interactionDetails).toHaveBeenLastCalledWith(request, response);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,13 +4,11 @@ import {
|
||||
import type { AccountStore } from '../../../../../../src/identity/interaction/email-password/storage/AccountStore';
|
||||
import type { EmailSender } from '../../../../../../src/identity/interaction/util/EmailSender';
|
||||
import type { HttpRequest } from '../../../../../../src/server/HttpRequest';
|
||||
import type { HttpResponse } from '../../../../../../src/server/HttpResponse';
|
||||
import type { TemplateEngine } from '../../../../../../src/util/templates/TemplateEngine';
|
||||
import { createPostFormRequest } from './Util';
|
||||
|
||||
describe('A ForgotPasswordHandler', (): void => {
|
||||
let request: HttpRequest;
|
||||
const response: HttpResponse = {} as any;
|
||||
const email = 'test@test.email';
|
||||
const recordId = '123456';
|
||||
const html = `<a href="/base/idp/resetpassword/${recordId}">Reset Password</a>`;
|
||||
@@ -47,20 +45,20 @@ describe('A ForgotPasswordHandler', (): void => {
|
||||
|
||||
it('errors on non-string emails.', async(): Promise<void> => {
|
||||
request = createPostFormRequest({});
|
||||
await expect(handler.handle({ request, response })).rejects.toThrow('Email required');
|
||||
await expect(handler.handle({ request })).rejects.toThrow('Email required');
|
||||
request = createPostFormRequest({ email: [ 'email', 'email2' ]});
|
||||
await expect(handler.handle({ request, response })).rejects.toThrow('Email required');
|
||||
await expect(handler.handle({ request })).rejects.toThrow('Email required');
|
||||
});
|
||||
|
||||
it('does not send a mail if a ForgotPassword record could not be generated.', async(): Promise<void> => {
|
||||
(accountStore.generateForgotPasswordRecord as jest.Mock).mockRejectedValueOnce('error');
|
||||
await expect(handler.handle({ request, response })).resolves
|
||||
await expect(handler.handle({ request })).resolves
|
||||
.toEqual({ type: 'response', details: { email }});
|
||||
expect(emailSender.handleSafe).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('sends a mail if a ForgotPassword record could be generated.', async(): Promise<void> => {
|
||||
await expect(handler.handle({ request, response })).resolves
|
||||
await expect(handler.handle({ request })).resolves
|
||||
.toEqual({ type: 'response', details: { email }});
|
||||
expect(emailSender.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(emailSender.handleSafe).toHaveBeenLastCalledWith({
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import type {
|
||||
InteractionHandlerInput,
|
||||
} from '../../../../../../src/identity/interaction/email-password/handler/InteractionHandler';
|
||||
import { LoginHandler } from '../../../../../../src/identity/interaction/email-password/handler/LoginHandler';
|
||||
import type { AccountStore } from '../../../../../../src/identity/interaction/email-password/storage/AccountStore';
|
||||
import type { HttpHandlerInput } from '../../../../../../src/server/HttpHandler';
|
||||
import { createPostFormRequest } from './Util';
|
||||
|
||||
describe('A LoginHandler', (): void => {
|
||||
const webId = 'http://alice.test.com/card#me';
|
||||
const email = 'alice@test.email';
|
||||
let input: HttpHandlerInput;
|
||||
let input: InteractionHandlerInput;
|
||||
let storageAdapter: AccountStore;
|
||||
let handler: LoginHandler;
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import type { IdentifierGenerator } from '../../../../../../src/pods/generate/Id
|
||||
import type { PodManager } from '../../../../../../src/pods/PodManager';
|
||||
import type { PodSettings } from '../../../../../../src/pods/settings/PodSettings';
|
||||
import type { HttpRequest } from '../../../../../../src/server/HttpRequest';
|
||||
import type { HttpResponse } from '../../../../../../src/server/HttpResponse';
|
||||
import { createPostFormRequest } from './Util';
|
||||
|
||||
describe('A RegistrationHandler', (): void => {
|
||||
@@ -27,7 +26,6 @@ describe('A RegistrationHandler', (): void => {
|
||||
const createPod = 'true';
|
||||
|
||||
let request: HttpRequest;
|
||||
const response: HttpResponse = {} as any;
|
||||
|
||||
const baseUrl = 'http://test.com/';
|
||||
const webIdSuffix = '/profile/card';
|
||||
@@ -72,71 +70,71 @@ describe('A RegistrationHandler', (): void => {
|
||||
describe('validating data', (): void => {
|
||||
it('rejects array inputs.', async(): Promise<void> => {
|
||||
request = createPostFormRequest({ mydata: [ 'a', 'b' ]});
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Unexpected multiple values for mydata.');
|
||||
});
|
||||
|
||||
it('errors on invalid emails.', async(): Promise<void> => {
|
||||
request = createPostFormRequest({ email: undefined });
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Please enter a valid e-mail address.');
|
||||
|
||||
request = createPostFormRequest({ email: '' });
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Please enter a valid e-mail address.');
|
||||
|
||||
request = createPostFormRequest({ email: 'invalidEmail' });
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Please enter a valid e-mail address.');
|
||||
});
|
||||
|
||||
it('errors when a required WebID is not valid.', async(): Promise<void> => {
|
||||
request = createPostFormRequest({ email, register, webId: undefined });
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Please enter a valid WebID.');
|
||||
|
||||
request = createPostFormRequest({ email, register, webId: '' });
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Please enter a valid WebID.');
|
||||
});
|
||||
|
||||
it('errors on invalid passwords when registering.', async(): Promise<void> => {
|
||||
request = createPostFormRequest({ email, webId, password, confirmPassword: 'bad', register });
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Your password and confirmation did not match.');
|
||||
});
|
||||
|
||||
it('errors on invalid pod names when required.', async(): Promise<void> => {
|
||||
request = createPostFormRequest({ email, webId, createPod, podName: undefined });
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Please specify a Pod name.');
|
||||
|
||||
request = createPostFormRequest({ email, webId, createPod, podName: ' ' });
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Please specify a Pod name.');
|
||||
|
||||
request = createPostFormRequest({ email, webId, createWebId });
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Please specify a Pod name.');
|
||||
});
|
||||
|
||||
it('errors when trying to create a WebID without registering or creating a pod.', async(): Promise<void> => {
|
||||
request = createPostFormRequest({ email, podName, createWebId });
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Please enter a password.');
|
||||
|
||||
request = createPostFormRequest({ email, podName, createWebId, createPod });
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Please enter a password.');
|
||||
|
||||
request = createPostFormRequest({ email, podName, createWebId, createPod, register });
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Please enter a password.');
|
||||
});
|
||||
|
||||
it('errors when no option is chosen.', async(): Promise<void> => {
|
||||
request = createPostFormRequest({ email, webId });
|
||||
await expect(handler.handle({ request, response }))
|
||||
await expect(handler.handle({ request }))
|
||||
.rejects.toThrow('Please register for a WebID or create a Pod.');
|
||||
});
|
||||
});
|
||||
@@ -144,7 +142,7 @@ describe('A RegistrationHandler', (): void => {
|
||||
describe('handling data', (): void => {
|
||||
it('can register a user.', async(): Promise<void> => {
|
||||
request = createPostFormRequest({ email, webId, password, confirmPassword, register });
|
||||
await expect(handler.handle({ request, response })).resolves.toEqual({
|
||||
await expect(handler.handle({ request })).resolves.toEqual({
|
||||
details: {
|
||||
email,
|
||||
webId,
|
||||
@@ -171,7 +169,7 @@ describe('A RegistrationHandler', (): void => {
|
||||
it('can create a pod.', async(): Promise<void> => {
|
||||
const params = { email, webId, podName, createPod };
|
||||
request = createPostFormRequest(params);
|
||||
await expect(handler.handle({ request, response })).resolves.toEqual({
|
||||
await expect(handler.handle({ request })).resolves.toEqual({
|
||||
details: {
|
||||
email,
|
||||
webId,
|
||||
@@ -200,7 +198,7 @@ describe('A RegistrationHandler', (): void => {
|
||||
const params = { email, webId, password, confirmPassword, podName, register, createPod };
|
||||
podSettings.oidcIssuer = baseUrl;
|
||||
request = createPostFormRequest(params);
|
||||
await expect(handler.handle({ request, response })).resolves.toEqual({
|
||||
await expect(handler.handle({ request })).resolves.toEqual({
|
||||
details: {
|
||||
email,
|
||||
webId,
|
||||
@@ -232,7 +230,7 @@ describe('A RegistrationHandler', (): void => {
|
||||
podSettings.oidcIssuer = baseUrl;
|
||||
request = createPostFormRequest(params);
|
||||
(podManager.createPod as jest.Mock).mockRejectedValueOnce(new Error('pod error'));
|
||||
await expect(handler.handle({ request, response })).rejects.toThrow('pod error');
|
||||
await expect(handler.handle({ request })).rejects.toThrow('pod error');
|
||||
|
||||
expect(ownershipValidator.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(ownershipValidator.handleSafe).toHaveBeenLastCalledWith({ webId });
|
||||
@@ -255,7 +253,7 @@ describe('A RegistrationHandler', (): void => {
|
||||
podSettings.oidcIssuer = baseUrl;
|
||||
|
||||
request = createPostFormRequest(params);
|
||||
await expect(handler.handle({ request, response })).resolves.toEqual({
|
||||
await expect(handler.handle({ request })).resolves.toEqual({
|
||||
details: {
|
||||
email,
|
||||
webId: generatedWebID,
|
||||
@@ -285,7 +283,7 @@ describe('A RegistrationHandler', (): void => {
|
||||
const params = { email, webId, podName, createPod };
|
||||
request = createPostFormRequest(params);
|
||||
(podManager.createPod as jest.Mock).mockRejectedValueOnce(new Error('pod error'));
|
||||
const prom = handler.handle({ request, response });
|
||||
const prom = handler.handle({ request });
|
||||
await expect(prom).rejects.toThrow('pod error');
|
||||
await expect(prom).rejects.toThrow(IdpInteractionError);
|
||||
// Using the cleaned input for prefilled
|
||||
|
||||
@@ -3,12 +3,10 @@ import {
|
||||
} from '../../../../../../src/identity/interaction/email-password/handler/ResetPasswordHandler';
|
||||
import type { AccountStore } from '../../../../../../src/identity/interaction/email-password/storage/AccountStore';
|
||||
import type { HttpRequest } from '../../../../../../src/server/HttpRequest';
|
||||
import type { HttpResponse } from '../../../../../../src/server/HttpResponse';
|
||||
import { createPostFormRequest } from './Util';
|
||||
|
||||
describe('A ResetPasswordHandler', (): void => {
|
||||
let request: HttpRequest;
|
||||
const response: HttpResponse = {} as any;
|
||||
const recordId = '123456';
|
||||
const url = `/resetURL/${recordId}`;
|
||||
const email = 'alice@test.email';
|
||||
@@ -28,27 +26,27 @@ describe('A ResetPasswordHandler', (): void => {
|
||||
it('errors for non-string recordIds.', async(): Promise<void> => {
|
||||
const errorMessage = 'Invalid request. Open the link from your email again';
|
||||
request = createPostFormRequest({});
|
||||
await expect(handler.handle({ request, response })).rejects.toThrow(errorMessage);
|
||||
await expect(handler.handle({ request })).rejects.toThrow(errorMessage);
|
||||
request = createPostFormRequest({}, '');
|
||||
await expect(handler.handle({ request, response })).rejects.toThrow(errorMessage);
|
||||
await expect(handler.handle({ request })).rejects.toThrow(errorMessage);
|
||||
});
|
||||
|
||||
it('errors for invalid passwords.', async(): Promise<void> => {
|
||||
const errorMessage = 'Your password and confirmation did not match.';
|
||||
request = createPostFormRequest({ password: 'password!', confirmPassword: 'otherPassword!' }, url);
|
||||
await expect(handler.handle({ request, response })).rejects.toThrow(errorMessage);
|
||||
await expect(handler.handle({ request })).rejects.toThrow(errorMessage);
|
||||
});
|
||||
|
||||
it('errors for invalid emails.', async(): Promise<void> => {
|
||||
const errorMessage = 'This reset password link is no longer valid.';
|
||||
request = createPostFormRequest({ password: 'password!', confirmPassword: 'password!' }, url);
|
||||
(accountStore.getForgotPasswordRecord as jest.Mock).mockResolvedValueOnce(undefined);
|
||||
await expect(handler.handle({ request, response })).rejects.toThrow(errorMessage);
|
||||
await expect(handler.handle({ request })).rejects.toThrow(errorMessage);
|
||||
});
|
||||
|
||||
it('renders a message on success.', async(): Promise<void> => {
|
||||
request = createPostFormRequest({ password: 'password!', confirmPassword: 'password!' }, url);
|
||||
await expect(handler.handle({ request, response })).resolves.toEqual({ type: 'response' });
|
||||
await expect(handler.handle({ request })).resolves.toEqual({ type: 'response' });
|
||||
expect(accountStore.getForgotPasswordRecord).toHaveBeenCalledTimes(1);
|
||||
expect(accountStore.getForgotPasswordRecord).toHaveBeenLastCalledWith(recordId);
|
||||
expect(accountStore.deleteForgotPasswordRecord).toHaveBeenCalledTimes(1);
|
||||
@@ -61,6 +59,6 @@ describe('A ResetPasswordHandler', (): void => {
|
||||
const errorMessage = 'Unknown error: not native';
|
||||
request = createPostFormRequest({ password: 'password!', confirmPassword: 'password!' }, url);
|
||||
(accountStore.getForgotPasswordRecord as jest.Mock).mockRejectedValueOnce('not native');
|
||||
await expect(handler.handle({ request, response })).rejects.toThrow(errorMessage);
|
||||
await expect(handler.handle({ request })).rejects.toThrow(errorMessage);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user