diff --git a/.vscode/launch.json b/.vscode/launch.json index 7a10c5b1d063b..ec3f80a537e8c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -68,7 +68,8 @@ ], "env": { "NODE_ENV": "development", - "THEIA_WEBVIEW_EXTERNAL_ENDPOINT": "${env:THEIA_WEBVIEW_EXTERNAL_ENDPOINT}" + "THEIA_WEBVIEW_EXTERNAL_ENDPOINT": "${env:THEIA_WEBVIEW_EXTERNAL_ENDPOINT}", + "THEIA_MINI_BROWSER_HOST_PATTERN": "${env:THEIA_MINI_BROWSER_HOST_PATTERN}" }, "sourceMaps": true, "outFiles": [ @@ -110,7 +111,8 @@ ], "env": { "NODE_ENV": "development", - "THEIA_WEBVIEW_EXTERNAL_ENDPOINT": "${env:THEIA_WEBVIEW_EXTERNAL_ENDPOINT}" + "THEIA_WEBVIEW_EXTERNAL_ENDPOINT": "${env:THEIA_WEBVIEW_EXTERNAL_ENDPOINT}", + "THEIA_MINI_BROWSER_HOST_PATTERN": "${env:THEIA_MINI_BROWSER_HOST_PATTERN}" }, "sourceMaps": true, "outFiles": [ @@ -173,7 +175,8 @@ ], "env": { "THEIA_DEFAULT_PLUGINS": "local-dir:${workspaceFolder}/plugins", - "THEIA_WEBVIEW_EXTERNAL_ENDPOINT": "${env:THEIA_WEBVIEW_EXTERNAL_ENDPOINT}" + "THEIA_WEBVIEW_EXTERNAL_ENDPOINT": "${env:THEIA_WEBVIEW_EXTERNAL_ENDPOINT}", + "THEIA_MINI_BROWSER_HOST_PATTERN": "${env:THEIA_MINI_BROWSER_HOST_PATTERN}" }, "stopOnEntry": false, "sourceMaps": true, diff --git a/packages/mini-browser/src/browser/environment/mini-browser-environment.ts b/packages/mini-browser/src/browser/environment/mini-browser-environment.ts index fdcb8796c5246..37a3363536fda 100644 --- a/packages/mini-browser/src/browser/environment/mini-browser-environment.ts +++ b/packages/mini-browser/src/browser/environment/mini-browser-environment.ts @@ -44,6 +44,7 @@ export class MiniBrowserEnvironment implements FrontendApplicationContribution { getEndpoint(uuid: string, hostname?: string): Endpoint { return new Endpoint({ + path: MiniBrowserEndpoint.PATH, host: this._hostPattern .replace('{{uuid}}', uuid) .replace('{{hostname}}', hostname || this.getDefaultHostname()), diff --git a/packages/mini-browser/src/common/mini-browser-endpoint.ts b/packages/mini-browser/src/common/mini-browser-endpoint.ts index 5999e7e60c927..575bdc9b45414 100644 --- a/packages/mini-browser/src/common/mini-browser-endpoint.ts +++ b/packages/mini-browser/src/common/mini-browser-endpoint.ts @@ -22,6 +22,7 @@ * will be replace by a random uuid value. */ export namespace MiniBrowserEndpoint { + export const PATH = '/mini-browser'; export const HOST_PATTERN_ENV = 'THEIA_MINI_BROWSER_HOST_PATTERN'; export const HOST_PATTERN_DEFAULT = '{{uuid}}.mini-browser.{{hostname}}'; } diff --git a/packages/mini-browser/src/node/mini-browser-endpoint.ts b/packages/mini-browser/src/node/mini-browser-endpoint.ts index e591c0d270d1a..6df45614401b7 100644 --- a/packages/mini-browser/src/node/mini-browser-endpoint.ts +++ b/packages/mini-browser/src/node/mini-browser-endpoint.ts @@ -115,7 +115,7 @@ export class MiniBrowserEndpoint implements BackendApplicationContribution, Mini protected async attachRequestHandler(app: Application): Promise { const miniBrowserApp = express(); miniBrowserApp.get('*', async (request, response) => this.response(await this.getUri(request), response)); - app.use(vhost(await this.getVirtualHostRegExp(), miniBrowserApp)); + app.use(MiniBrowserEndpointNS.PATH, vhost(await this.getVirtualHostRegExp(), miniBrowserApp)); } protected async response(uri: string, response: Response): Promise { diff --git a/packages/mini-browser/src/node/mini-browser-ws-validator.ts b/packages/mini-browser/src/node/mini-browser-ws-validator.ts index 0fb139a76b2f6..6ded1d544f21d 100644 --- a/packages/mini-browser/src/node/mini-browser-ws-validator.ts +++ b/packages/mini-browser/src/node/mini-browser-ws-validator.ts @@ -28,18 +28,23 @@ export class MiniBrowserWsRequestValidator implements WsRequestValidatorContribu protected miniBrowserHostRe: RegExp; + protected serveSameOrigin: boolean = false; + @postConstruct() protected postConstruct(): void { const pattern = process.env[MiniBrowserEndpoint.HOST_PATTERN_ENV] || MiniBrowserEndpoint.HOST_PATTERN_DEFAULT; + if (pattern === '{{hostname}}') { + this.serveSameOrigin = true; + } const vhostRe = pattern - .replace('.', '\\.') + .replace(/\./g, '\\.') .replace('{{uuid}}', '.+') .replace('{{hostname}}', '.+'); this.miniBrowserHostRe = new RegExp(vhostRe, 'i'); } async allowWsUpgrade(request: http.IncomingMessage): Promise { - if (request.headers.origin) { + if (request.headers.origin && !this.serveSameOrigin) { const origin = url.parse(request.headers.origin); if (origin.host && this.miniBrowserHostRe.test(origin.host)) { // If the origin comes from the WebViews, refuse: diff --git a/packages/plugin-ext/src/main/node/plugin-service.ts b/packages/plugin-ext/src/main/node/plugin-service.ts index 965c184b02061..d2de54b578763 100644 --- a/packages/plugin-ext/src/main/node/plugin-service.ts +++ b/packages/plugin-ext/src/main/node/plugin-service.ts @@ -31,6 +31,8 @@ export class PluginApiContribution implements BackendApplicationContribution, Ws protected webviewExternalEndpointRegExp: RegExp; + protected serveSameOrigin: boolean = false; + @postConstruct() protected postConstruct(): void { const webviewExternalEndpoint = this.webviewExternalEndpoint(); @@ -45,7 +47,7 @@ export class PluginApiContribution implements BackendApplicationContribution, Ws } allowWsUpgrade(request: http.IncomingMessage): MaybePromise { - if (request.headers.origin) { + if (request.headers.origin && !this.serveSameOrigin) { const origin = url.parse(request.headers.origin); if (origin.host && this.webviewExternalEndpointRegExp.test(origin.host)) { // If the origin comes from the WebViews, refuse: @@ -55,17 +57,25 @@ export class PluginApiContribution implements BackendApplicationContribution, Ws return true; } - /** - * Returns a RegExp pattern matching the expected WebView endpoint's host. - */ - protected webviewExternalEndpoint(): string { + protected webviewExternalEndpointPattern(): string { let endpointPattern; if (environment.electron.is()) { endpointPattern = WebviewExternalEndpoint.defaultPattern; } else { endpointPattern = process.env[WebviewExternalEndpoint.pattern] || WebviewExternalEndpoint.defaultPattern; } - return `^${endpointPattern + if (endpointPattern === '{{hostname}}') { + this.serveSameOrigin = true; + } + return endpointPattern; + } + + /** + * Returns a RegExp pattern matching the expected WebView endpoint's host. + */ + protected webviewExternalEndpoint(): string { + return `^${this.webviewExternalEndpointPattern() + .replace(/\./g, '\\.') .replace('{{uuid}}', '.+') .replace('{{hostname}}', '.+')}$`; }