Skip to content

Commit

Permalink
Merge 24f7171 into 2d1d098
Browse files Browse the repository at this point in the history
  • Loading branch information
joachimvh committed Jul 26, 2021
2 parents 2d1d098 + 24f7171 commit fbbf0ee
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { ResourceIdentifier } from '../../../../ldp/representation/Resource
import { getLoggerFor } from '../../../../logging/LogUtil';
import type { IdentifierGenerator } from '../../../../pods/generate/IdentifierGenerator';
import type { PodManager } from '../../../../pods/PodManager';
import type { PodSettings } from '../../../../pods/settings/PodSettings';
import type { HttpHandlerInput } from '../../../../server/HttpHandler';
import { HttpHandler } from '../../../../server/HttpHandler';
import type { HttpRequest } from '../../../../server/HttpRequest';
Expand Down Expand Up @@ -48,17 +49,29 @@ export interface RegistrationHandlerArgs {

/**
* All the parameters that will be parsed from a request.
* `data` contains all the raw values to potentially be used by pod templates.
*/
interface ParseResult {
interface ParsedInput {
email: string;
webId?: string;
password?: string;
podName?: string;
template?: string;
createWebId: boolean;
register: boolean;
createPod: boolean;
}

/**
* The results that will be applied to the response template.
*/
interface RegistrationResponse {
email: string;
webId?: string;
oidcIssuer?: string;
podBaseUrl?: string;
createWebId: boolean;
register: boolean;
createPod: boolean;
data: NodeJS.Dict<string>;
}

/**
Expand Down Expand Up @@ -103,43 +116,51 @@ export class RegistrationHandler extends HttpHandler {
const contents = await this.register(result);
await this.responseHandler.handleSafe({ response, contents });
} catch (error: unknown) {
throwIdpInteractionError(error, result.data as Record<string, string>);
// Don't expose the password field
delete result.password;
throwIdpInteractionError(error, result as Record<string, any>);
}
}

/**
* Does the full registration and pod creation process,
* with the steps chosen by the values in the `ParseResult`.
*/
private async register(result: ParseResult): Promise<NodeJS.Dict<any>> {
private async register(result: ParsedInput): Promise<RegistrationResponse> {
// This is only used when createWebId and/or createPod are true
let podBaseUrl: ResourceIdentifier | undefined;
if (result.createWebId || result.createPod) {
podBaseUrl = this.identifierGenerator.generate(result.podName!);
}

// Create or verify the WebID
if (result.createWebId) {
podBaseUrl = this.identifierGenerator.generate(result.podName!);
result.webId = urljoin(podBaseUrl.path, this.webIdSuffix);
result.webId = urljoin(podBaseUrl!.path, this.webIdSuffix);
} else {
await this.ownershipValidator.handleSafe({ webId: result.webId! });
}

// Register the account
if (result.register) {
await this.accountStore.create(result.email, result.webId!, result.password!);

// Add relevant data for the templates
result.data.oidcIssuer = this.baseUrl;
}

// Create the pod
if (result.createPod) {
podBaseUrl = podBaseUrl ?? this.identifierGenerator.generate(result.podName!);
const podSettings: PodSettings = {
email: result.email,
webId: result.webId!,
template: result.template,
podBaseUrl: podBaseUrl!.path,
};

// Set the OIDC issuer to our server when registering with the IDP
if (result.register) {
podSettings.oidcIssuer = this.baseUrl;
}

try {
await this.podManager.createPod(podBaseUrl, {
...result.data,
podBaseUrl: podBaseUrl.path,
webId: result.webId!,
});
await this.podManager.createPod(podBaseUrl!, podSettings);
} catch (error: unknown) {
// In case pod creation errors we don't want to keep the account
if (result.register) {
Expand Down Expand Up @@ -170,7 +191,7 @@ export class RegistrationHandler extends HttpHandler {
/**
* Parses the input request into a `ParseResult`.
*/
private async parseInput(request: HttpRequest): Promise<ParseResult> {
private async parseInput(request: HttpRequest): Promise<ParsedInput> {
const parsed = await getFormDataRequestBody(request);
let prefilled: Record<string, string> = {};
try {
Expand All @@ -190,18 +211,18 @@ export class RegistrationHandler extends HttpHandler {
* Converts the raw input date into a `ParseResult`.
* Verifies that all the data combinations make sense.
*/
private validateInput(parsed: NodeJS.Dict<string>): ParseResult {
const { email, password, confirmPassword, podName, webId, createWebId, register, createPod } = parsed;
private validateInput(parsed: NodeJS.Dict<string>): ParsedInput {
const { email, password, confirmPassword, podName, webId, template, createWebId, register, createPod } = parsed;

assert(typeof email === 'string' && email.length > 0 && emailRegex.test(email),
'A valid e-mail address is required');

const result: ParseResult = {
const result: ParsedInput = {
email,
template,
createWebId: Boolean(createWebId),
register: Boolean(register),
createPod: Boolean(createPod),
data: parsed,
};

const validWebId = typeof webId === 'string' && webId.length > 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { OwnershipValidator } from '../../../../../../src/identity/ownershi
import type { ResourceIdentifier } from '../../../../../../src/ldp/representation/ResourceIdentifier';
import type { IdentifierGenerator } from '../../../../../../src/pods/generate/IdentifierGenerator';
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 type { TemplateHandler } from '../../../../../../src/server/util/TemplateHandler';
Expand All @@ -31,6 +32,7 @@ describe('A RegistrationHandler', (): void => {

const baseUrl = 'http://test.com/';
const webIdSuffix = '/profile/card';
let podSettings: PodSettings;
let identifierGenerator: IdentifierGenerator;
let ownershipValidator: OwnershipValidator;
let accountStore: AccountStore;
Expand All @@ -39,6 +41,8 @@ describe('A RegistrationHandler', (): void => {
let handler: RegistrationHandler;

beforeEach(async(): Promise<void> => {
podSettings = { email, webId, podBaseUrl };

identifierGenerator = {
generate: jest.fn((name: string): ResourceIdentifier => ({ path: `${baseUrl}${name}/` })),
};
Expand Down Expand Up @@ -179,9 +183,7 @@ describe('A RegistrationHandler', (): void => {
expect(identifierGenerator.generate).toHaveBeenCalledTimes(1);
expect(identifierGenerator.generate).toHaveBeenLastCalledWith(podName);
expect(podManager.createPod).toHaveBeenCalledTimes(1);
expect(podManager.createPod).toHaveBeenLastCalledWith(
{ path: `${baseUrl}${podName}/` }, { podBaseUrl, ...params },
);
expect(podManager.createPod).toHaveBeenLastCalledWith({ path: `${baseUrl}${podName}/` }, podSettings);

expect(accountStore.create).toHaveBeenCalledTimes(0);
expect(accountStore.verify).toHaveBeenCalledTimes(0);
Expand All @@ -190,6 +192,7 @@ describe('A RegistrationHandler', (): void => {

it('adds an oidcIssuer to the data when doing both IDP registration and pod creation.', async(): Promise<void> => {
const params = { email, webId, password, confirmPassword, podName, register, createPod };
podSettings.oidcIssuer = baseUrl;
request = createPostFormRequest(params);
await expect(handler.handle({ request, response })).resolves.toBeUndefined();

Expand All @@ -199,11 +202,8 @@ describe('A RegistrationHandler', (): void => {
expect(accountStore.create).toHaveBeenLastCalledWith(email, webId, password);
expect(identifierGenerator.generate).toHaveBeenCalledTimes(1);
expect(identifierGenerator.generate).toHaveBeenLastCalledWith(podName);
(params as any).oidcIssuer = baseUrl;
expect(podManager.createPod).toHaveBeenCalledTimes(1);
expect(podManager.createPod).toHaveBeenLastCalledWith(
{ path: `${baseUrl}${podName}/` }, { podBaseUrl, ...params },
);
expect(podManager.createPod).toHaveBeenLastCalledWith({ path: `${baseUrl}${podName}/` }, podSettings);
expect(accountStore.verify).toHaveBeenCalledTimes(1);
expect(accountStore.verify).toHaveBeenLastCalledWith(email);

Expand All @@ -212,6 +212,7 @@ describe('A RegistrationHandler', (): void => {

it('deletes the created account if pod generation fails.', async(): Promise<void> => {
const params = { email, webId, password, confirmPassword, podName, register, createPod };
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');
Expand All @@ -222,11 +223,8 @@ describe('A RegistrationHandler', (): void => {
expect(accountStore.create).toHaveBeenLastCalledWith(email, webId, password);
expect(identifierGenerator.generate).toHaveBeenCalledTimes(1);
expect(identifierGenerator.generate).toHaveBeenLastCalledWith(podName);
(params as any).oidcIssuer = baseUrl;
expect(podManager.createPod).toHaveBeenCalledTimes(1);
expect(podManager.createPod).toHaveBeenLastCalledWith(
{ path: `${baseUrl}${podName}/` }, { podBaseUrl, ...params },
);
expect(podManager.createPod).toHaveBeenLastCalledWith({ path: `${baseUrl}${podName}/` }, podSettings);
expect(accountStore.deleteAccount).toHaveBeenCalledTimes(1);
expect(accountStore.deleteAccount).toHaveBeenLastCalledWith(email);

Expand All @@ -235,10 +233,12 @@ describe('A RegistrationHandler', (): void => {

it('can create a WebID with an account and pod.', async(): Promise<void> => {
const params = { email, password, confirmPassword, podName, createWebId, register, createPod };
podSettings.oidcIssuer = baseUrl;
request = createPostFormRequest(params);
await expect(handler.handle({ request, response })).resolves.toBeUndefined();

const generatedWebID = urljoin(baseUrl, podName, webIdSuffix);
podSettings.webId = generatedWebID;

expect(identifierGenerator.generate).toHaveBeenCalledTimes(1);
expect(identifierGenerator.generate).toHaveBeenLastCalledWith(podName);
Expand All @@ -247,9 +247,7 @@ describe('A RegistrationHandler', (): void => {
expect(accountStore.verify).toHaveBeenCalledTimes(1);
expect(accountStore.verify).toHaveBeenLastCalledWith(email);
expect(podManager.createPod).toHaveBeenCalledTimes(1);
expect(podManager.createPod).toHaveBeenLastCalledWith(
{ path: `${baseUrl}${podName}/` }, { ...params, podBaseUrl, oidcIssuer: baseUrl, webId: generatedWebID },
);
expect(podManager.createPod).toHaveBeenLastCalledWith({ path: `${baseUrl}${podName}/` }, podSettings);

expect(ownershipValidator.handleSafe).toHaveBeenCalledTimes(0);
expect(accountStore.deleteAccount).toHaveBeenCalledTimes(0);
Expand All @@ -262,7 +260,13 @@ describe('A RegistrationHandler', (): void => {
const prom = handler.handle({ request, response });
await expect(prom).rejects.toThrow('pod error');
await expect(prom).rejects.toThrow(IdpInteractionError);
await expect(prom).rejects.toThrow(expect.objectContaining({ prefilled: params }));
// Using the cleaned input for prefilled
await expect(prom).rejects.toThrow(expect.objectContaining({ prefilled: {
...params,
createWebId: false,
register: false,
createPod: true,
}}));
});
});
});

0 comments on commit fbbf0ee

Please sign in to comment.