mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Remove setup
This commit is contained in:
@@ -209,10 +209,6 @@ export * from './init/final/Finalizable';
|
||||
export * from './init/final/FinalizableHandler';
|
||||
export * from './init/final/Finalizer';
|
||||
|
||||
// Init/Setup
|
||||
export * from './init/setup/SetupHandler';
|
||||
export * from './init/setup/SetupHttpHandler';
|
||||
|
||||
// Init/Cli
|
||||
export * from './init/cli/CliExtractor';
|
||||
export * from './init/cli/YargsCliExtractor';
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
import { BasicRepresentation } from '../../http/representation/BasicRepresentation';
|
||||
import type { Representation } from '../../http/representation/Representation';
|
||||
import { BaseInteractionHandler } from '../../identity/interaction/BaseInteractionHandler';
|
||||
import type { RegistrationManager } from '../../identity/interaction/email-password/util/RegistrationManager';
|
||||
import type { InteractionHandlerInput } from '../../identity/interaction/InteractionHandler';
|
||||
import { getLoggerFor } from '../../logging/LogUtil';
|
||||
import { APPLICATION_JSON } from '../../util/ContentTypes';
|
||||
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError';
|
||||
import { readJsonStream } from '../../util/StreamUtil';
|
||||
import type { Initializer } from '../Initializer';
|
||||
|
||||
export interface SetupHandlerArgs {
|
||||
/**
|
||||
* Used for registering a pod during setup.
|
||||
*/
|
||||
registrationManager?: RegistrationManager;
|
||||
/**
|
||||
* Initializer to call in case no registration procedure needs to happen.
|
||||
* This Initializer should make sure the necessary resources are there so the server can work correctly.
|
||||
*/
|
||||
initializer?: Initializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* On POST requests, runs an initializer and/or performs a registration step, both optional.
|
||||
*/
|
||||
export class SetupHandler extends BaseInteractionHandler {
|
||||
protected readonly logger = getLoggerFor(this);
|
||||
|
||||
private readonly registrationManager?: RegistrationManager;
|
||||
private readonly initializer?: Initializer;
|
||||
|
||||
public constructor(args: SetupHandlerArgs) {
|
||||
super({});
|
||||
this.registrationManager = args.registrationManager;
|
||||
this.initializer = args.initializer;
|
||||
}
|
||||
|
||||
protected async handlePost({ operation }: InteractionHandlerInput): Promise<Representation> {
|
||||
const json = operation.body.isEmpty ? {} : await readJsonStream(operation.body.data);
|
||||
|
||||
const output: Record<string, any> = { initialize: false, registration: false };
|
||||
if (json.registration) {
|
||||
Object.assign(output, await this.register(json));
|
||||
output.registration = true;
|
||||
} else if (json.initialize) {
|
||||
// We only want to initialize if no registration happened
|
||||
await this.initialize();
|
||||
output.initialize = true;
|
||||
}
|
||||
|
||||
this.logger.debug(`Output: ${JSON.stringify(output)}`);
|
||||
|
||||
return new BasicRepresentation(JSON.stringify(output), APPLICATION_JSON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the initializer.
|
||||
* Errors if no initializer was defined.
|
||||
*/
|
||||
private async initialize(): Promise<void> {
|
||||
if (!this.initializer) {
|
||||
throw new NotImplementedHttpError('This server is not configured with a setup initializer.');
|
||||
}
|
||||
await this.initializer.handleSafe();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a user based on the given input.
|
||||
* Errors if no registration manager is defined.
|
||||
*/
|
||||
private async register(json: NodeJS.Dict<any>): Promise<Record<string, any>> {
|
||||
if (!this.registrationManager) {
|
||||
throw new NotImplementedHttpError('This server is not configured to support registration during setup.');
|
||||
}
|
||||
// Validate the input JSON
|
||||
const validated = this.registrationManager.validateInput(json, true);
|
||||
this.logger.debug(`Validated input: ${JSON.stringify(validated)}`);
|
||||
|
||||
// Register and/or create a pod as requested. Potentially does nothing if all booleans are false.
|
||||
return this.registrationManager.register(validated, true);
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
import type { Operation } from '../../http/Operation';
|
||||
import { OkResponseDescription } from '../../http/output/response/OkResponseDescription';
|
||||
import type { ResponseDescription } from '../../http/output/response/ResponseDescription';
|
||||
import { BasicRepresentation } from '../../http/representation/BasicRepresentation';
|
||||
import type { InteractionHandler } from '../../identity/interaction/InteractionHandler';
|
||||
import { getLoggerFor } from '../../logging/LogUtil';
|
||||
import type { OperationHttpHandlerInput } from '../../server/OperationHttpHandler';
|
||||
import { OperationHttpHandler } from '../../server/OperationHttpHandler';
|
||||
import type { RepresentationConverter } from '../../storage/conversion/RepresentationConverter';
|
||||
import type { KeyValueStorage } from '../../storage/keyvalue/KeyValueStorage';
|
||||
import { APPLICATION_JSON, TEXT_HTML } from '../../util/ContentTypes';
|
||||
import { MethodNotAllowedHttpError } from '../../util/errors/MethodNotAllowedHttpError';
|
||||
import type { TemplateEngine } from '../../util/templates/TemplateEngine';
|
||||
|
||||
export interface SetupHttpHandlerArgs {
|
||||
/**
|
||||
* Used for converting the input data.
|
||||
*/
|
||||
converter: RepresentationConverter;
|
||||
/**
|
||||
* Handles the requests.
|
||||
*/
|
||||
handler: InteractionHandler;
|
||||
/**
|
||||
* Key that is used to store the boolean in the storage indicating setup is finished.
|
||||
*/
|
||||
storageKey: string;
|
||||
/**
|
||||
* Used to store setup status.
|
||||
*/
|
||||
storage: KeyValueStorage<string, boolean>;
|
||||
/**
|
||||
* Renders the main view.
|
||||
*/
|
||||
templateEngine: TemplateEngine;
|
||||
/**
|
||||
* Determines if pods can be created in the root of the server.
|
||||
* Relevant to make sure there are no nested storages if registration is enabled for example.
|
||||
* Defaults to `true`.
|
||||
*/
|
||||
allowRootPod?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the initial setup of a server.
|
||||
* Will capture all requests until setup is finished,
|
||||
* this to prevent accidentally running unsafe servers.
|
||||
*
|
||||
* GET requests will return the view template which should contain the setup information for the user.
|
||||
* POST requests will be sent to the InteractionHandler.
|
||||
* After successfully completing a POST request this handler will disable itself and become unreachable.
|
||||
* All other methods will be rejected.
|
||||
*/
|
||||
export class SetupHttpHandler extends OperationHttpHandler {
|
||||
protected readonly logger = getLoggerFor(this);
|
||||
|
||||
private readonly handler: InteractionHandler;
|
||||
private readonly converter: RepresentationConverter;
|
||||
private readonly storageKey: string;
|
||||
private readonly storage: KeyValueStorage<string, boolean>;
|
||||
private readonly templateEngine: TemplateEngine;
|
||||
private readonly allowRootPod: boolean;
|
||||
|
||||
public constructor(args: SetupHttpHandlerArgs) {
|
||||
super();
|
||||
|
||||
this.handler = args.handler;
|
||||
this.converter = args.converter;
|
||||
this.storageKey = args.storageKey;
|
||||
this.storage = args.storage;
|
||||
this.templateEngine = args.templateEngine;
|
||||
this.allowRootPod = args.allowRootPod ?? true;
|
||||
}
|
||||
|
||||
public async handle({ operation }: OperationHttpHandlerInput): Promise<ResponseDescription> {
|
||||
switch (operation.method) {
|
||||
case 'GET': return this.handleGet(operation);
|
||||
case 'POST': return this.handlePost(operation);
|
||||
default: throw new MethodNotAllowedHttpError([ operation.method ]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTML representation of the setup page.
|
||||
*/
|
||||
private async handleGet(operation: Operation): Promise<ResponseDescription> {
|
||||
const result = await this.templateEngine.handleSafe({ contents: { allowRootPod: this.allowRootPod }});
|
||||
const representation = new BasicRepresentation(result, operation.target, TEXT_HTML);
|
||||
return new OkResponseDescription(representation.metadata, representation.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the input data to JSON and calls the setup handler.
|
||||
* On success `true` will be written to the storage key.
|
||||
*/
|
||||
private async handlePost(operation: Operation): Promise<ResponseDescription> {
|
||||
// Convert input data to JSON
|
||||
// Allows us to still support form data
|
||||
if (operation.body.metadata.contentType) {
|
||||
const args = {
|
||||
representation: operation.body,
|
||||
preferences: { type: { [APPLICATION_JSON]: 1 }},
|
||||
identifier: operation.target,
|
||||
};
|
||||
operation = {
|
||||
...operation,
|
||||
body: await this.converter.handleSafe(args),
|
||||
};
|
||||
}
|
||||
|
||||
const representation = await this.handler.handleSafe({ operation });
|
||||
await this.storage.set(this.storageKey, true);
|
||||
|
||||
return new OkResponseDescription(representation.metadata, representation.data);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user