From dbc5c065f8a32f222a19d1057cf03d7cdd69788d Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 4 Feb 2020 16:55:27 -0600 Subject: [PATCH] Improve HTTP provider registration --- src/node/api/server.ts | 2 +- src/node/entry.ts | 19 ++++++++----------- src/node/http.ts | 33 ++++++++++++++++++++++++++++++--- src/node/vscode/server.ts | 2 +- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/node/api/server.ts b/src/node/api/server.ts index 10061530..7c3e6c8a 100644 --- a/src/node/api/server.ts +++ b/src/node/api/server.ts @@ -18,7 +18,7 @@ interface LoginPayload extends PostData { export class ApiHttpProvider extends HttpProvider { private readonly ws = new ws.Server({ noServer: true }) - public constructor(private readonly server: HttpServer, options: HttpProviderOptions) { + public constructor(options: HttpProviderOptions, private readonly server: HttpServer) { super(options) } diff --git a/src/node/entry.ts b/src/node/entry.ts index 4a77e98e..fa9a9916 100644 --- a/src/node/entry.ts +++ b/src/node/entry.ts @@ -20,6 +20,9 @@ export interface Args { } const main = async (args: Args = {}): Promise => { + const auth = args.auth || AuthType.Password + const originalPassword = auth === AuthType.Password && (process.env.PASSWORD || (await generatePassword())) + // Spawn the main HTTP server. const options = { basePath: args["base-path"], @@ -28,6 +31,8 @@ const main = async (args: Args = {}): Promise => { host: args.host || (args.auth === AuthType.Password && typeof args.cert !== "undefined" ? "0.0.0.0" : "localhost"), port: typeof args.port !== "undefined" ? parseInt(args.port, 10) : 8080, socket: args.socket, + auth, + password: originalPassword ? hash(originalPassword) : undefined, } if (!options.cert && typeof options.cert !== "undefined") { const { cert, certKey } = await generateCertificate() @@ -37,17 +42,9 @@ const main = async (args: Args = {}): Promise => { const httpServer = new HttpServer(options) // Register all the providers. - // TODO: Might be cleaner to be able to register with just the class name - // then let HttpServer instantiate with the common arguments. - const auth = args.auth || AuthType.Password - const originalPassword = auth === AuthType.Password && (process.env.PASSWORD || (await generatePassword())) - const password = originalPassword && hash(originalPassword) - httpServer.registerHttpProvider("/", new MainHttpProvider({ base: "/", auth, password })) - httpServer.registerHttpProvider("/api", new ApiHttpProvider(httpServer, { base: "/", auth, password })) - httpServer.registerHttpProvider( - "/vscode-embed", - new VscodeHttpProvider([], { base: "/vscode-embed", auth, password }) - ) + httpServer.registerHttpProvider("/", MainHttpProvider) + httpServer.registerHttpProvider("/api", ApiHttpProvider, httpServer) + httpServer.registerHttpProvider("/vscode-embed", VscodeHttpProvider, []) ipcMain().onDispose(() => httpServer.dispose()) diff --git a/src/node/http.ts b/src/node/http.ts index 3982bdb2..1588776e 100644 --- a/src/node/http.ts +++ b/src/node/http.ts @@ -88,10 +88,12 @@ export interface HttpStringFileResponse extends HttpResponse { } export interface HttpServerOptions { + readonly auth?: AuthType readonly basePath?: string readonly cert?: string readonly certKey?: string readonly host?: string + readonly password?: string readonly port?: number readonly socket?: string } @@ -108,7 +110,7 @@ interface ProviderRoute { export interface HttpProviderOptions { readonly base: string readonly auth: AuthType - readonly password: string | false + readonly password?: string } /** @@ -320,6 +322,14 @@ export class Heart { } } +export interface HttpProvider0 { + new (options: HttpProviderOptions): T +} + +export interface HttpProvider1 { + new (options: HttpProviderOptions, a1: A1): T +} + /** * An HTTP server. Its main role is to route incoming HTTP requests to the * appropriate provider for that endpoint then write out the response. It also @@ -372,7 +382,14 @@ export class HttpServer { /** * Register a provider for a top-level endpoint. */ - public registerHttpProvider(endpoint: string, provider: T): void { + public registerHttpProvider(endpoint: string, provider: HttpProvider0): void + public registerHttpProvider( + endpoint: string, + provider: HttpProvider1, + a1: A1 + ): void + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public registerHttpProvider(endpoint: string, provider: any, a1?: any): void { endpoint = endpoint.replace(/^\/+|\/+$/g, "") if (this.providers.has(`/${endpoint}`)) { throw new Error(`${endpoint} is already registered`) @@ -380,7 +397,17 @@ export class HttpServer { if (/\//.test(endpoint)) { throw new Error(`Only top-level endpoints are supported (got ${endpoint})`) } - this.providers.set(`/${endpoint}`, provider) + this.providers.set( + `/${endpoint}`, + new provider( + { + auth: this.options.auth || AuthType.None, + base: endpoint, + password: this.options.password, + }, + a1 + ) + ) } /** diff --git a/src/node/vscode/server.ts b/src/node/vscode/server.ts index 8b3d077c..e0c73637 100644 --- a/src/node/vscode/server.ts +++ b/src/node/vscode/server.ts @@ -24,7 +24,7 @@ export class VscodeHttpProvider extends HttpProvider { private _vscode?: Promise private workbenchOptions?: WorkbenchOptions - public constructor(private readonly args: string[], options: HttpProviderOptions) { + public constructor(options: HttpProviderOptions, private readonly args: string[]) { super(options) this.vsRootPath = path.resolve(this.rootPath, "lib/vscode") this.serverRootPath = path.join(this.vsRootPath, "out/vs/server")