Skip to content

Commit

Permalink
sandbox - allow to enable vscode-file protocol via argv or environment (
Browse files Browse the repository at this point in the history
  • Loading branch information
bpasero committed Jan 6, 2021
1 parent b165919 commit 169a0ec
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 56 deletions.
9 changes: 5 additions & 4 deletions src/bootstrap-window.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
const webFrame = preloadGlobals.webFrame;
const safeProcess = preloadGlobals.process;
const configuration = parseWindowConfiguration();
const useCustomProtocol = sandbox || typeof safeProcess.env['ENABLE_VSCODE_BROWSER_CODE_LOADING'] === 'string';

// Start to resolve process.env before anything gets load
// so that we can run loading and resolving in parallel
Expand Down Expand Up @@ -77,25 +78,25 @@
window.document.documentElement.setAttribute('lang', locale);

// do not advertise AMD to avoid confusing UMD modules loaded with nodejs
if (!sandbox) {
if (!useCustomProtocol) {
window['define'] = undefined;
}

// replace the patched electron fs with the original node fs for all AMD code (TODO@sandbox non-sandboxed only)
if (!sandbox) {
require.define('fs', ['original-fs'], function (originalFS) { return originalFS; });
require.define('fs', [], function () { return require.__$__nodeRequire('original-fs'); });
}

window['MonacoEnvironment'] = {};

const baseUrl = sandbox ?
const baseUrl = useCustomProtocol ?
`${bootstrapLib.fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32', scheme: 'vscode-file', fallbackAuthority: 'vscode-app' })}/out` :
`${bootstrapLib.fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32' })}/out`;

const loaderConfig = {
baseUrl,
'vs/nls': nlsConfig,
preferScriptTags: sandbox
preferScriptTags: useCustomProtocol
};

// Enable loading of node modules:
Expand Down
31 changes: 24 additions & 7 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,11 @@ function configureCommandlineSwitchesSync(cliArgs) {
const SUPPORTED_MAIN_PROCESS_SWITCHES = [

// Persistently enable proposed api via argv.json: https://github.com/microsoft/vscode/issues/99775
'enable-proposed-api'
'enable-proposed-api',

// TODO@bpasero remove me once testing is done on `vscode-file` protocol
// (all traces of `enable-browser-code-loading` and `ENABLE_VSCODE_BROWSER_CODE_LOADING`)
'enable-browser-code-loading'
];

// Read argv config
Expand Down Expand Up @@ -267,12 +271,20 @@ function configureCommandlineSwitchesSync(cliArgs) {

// Append main process flags to process.argv
else if (SUPPORTED_MAIN_PROCESS_SWITCHES.indexOf(argvKey) !== -1) {
if (argvKey === 'enable-proposed-api') {
if (Array.isArray(argvValue)) {
argvValue.forEach(id => id && typeof id === 'string' && process.argv.push('--enable-proposed-api', id));
} else {
console.error(`Unexpected value for \`enable-proposed-api\` in argv.json. Expected array of extension ids.`);
}
switch (argvKey) {
case 'enable-proposed-api':
if (Array.isArray(argvValue)) {
argvValue.forEach(id => id && typeof id === 'string' && process.argv.push('--enable-proposed-api', id));
} else {
console.error(`Unexpected value for \`enable-proposed-api\` in argv.json. Expected array of extension ids.`);
}
break;

case 'enable-browser-code-loading':
if (typeof argvValue === 'string') {
process.env['ENABLE_VSCODE_BROWSER_CODE_LOADING'] = argvValue;
}
break;
}
}
});
Expand All @@ -283,6 +295,11 @@ function configureCommandlineSwitchesSync(cliArgs) {
app.commandLine.appendSwitch('js-flags', jsFlags);
}

// Support __sandbox flag
if (cliArgs.__sandbox) {
process.env['ENABLE_VSCODE_BROWSER_CODE_LOADING'] = 'bypassHeatCheck';
}

return argvConfig;
}

Expand Down
42 changes: 14 additions & 28 deletions src/vs/base/common/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ class FileAccessImpl {
* **Note:** use `dom.ts#asCSSUrl` whenever the URL is to be used in CSS context.
*/
asBrowserUri(uri: URI): URI;
asBrowserUri(moduleId: string, moduleIdToUrl: { toUrl(moduleId: string): string }): URI;
asBrowserUri(uriOrModule: URI | string, moduleIdToUrl?: { toUrl(moduleId: string): string }): URI {
asBrowserUri(moduleId: string, moduleIdToUrl: { toUrl(moduleId: string): string }, __forceCodeFileUri?: boolean): URI;
asBrowserUri(uriOrModule: URI | string, moduleIdToUrl?: { toUrl(moduleId: string): string }, __forceCodeFileUri?: boolean): URI {
const uri = this.toUri(uriOrModule, moduleIdToUrl);

// Handle remote URIs via `RemoteAuthorities`
Expand All @@ -157,37 +157,23 @@ class FileAccessImpl {
}

// Only convert the URI if we are in a native context and it has `file:` scheme
if (platform.isElectronSandboxed && platform.isNative && uri.scheme === Schemas.file) {
return this.toCodeFileUri(uri);
// and we have explicitly enabled the conversion (sandbox, or ENABLE_VSCODE_BROWSER_CODE_LOADING)
if (platform.isNative && (__forceCodeFileUri || platform.isPreferringBrowserCodeLoad) && uri.scheme === Schemas.file) {
return uri.with({
scheme: Schemas.vscodeFileResource,
// We need to provide an authority here so that it can serve
// as origin for network and loading matters in chromium.
// If the URI is not coming with an authority already, we
// add our own
authority: uri.authority || this.FALLBACK_AUTHORITY,
query: null,
fragment: null
});
}

return uri;
}

/**
* TODO@bpasero remove me eventually when vscode-file is adopted everywhere
*/
_asCodeFileUri(uri: URI): URI;
_asCodeFileUri(moduleId: string, moduleIdToUrl: { toUrl(moduleId: string): string }): URI;
_asCodeFileUri(uriOrModule: URI | string, moduleIdToUrl?: { toUrl(moduleId: string): string }): URI {
const uri = this.toUri(uriOrModule, moduleIdToUrl);

return this.toCodeFileUri(uri);
}

private toCodeFileUri(uri: URI): URI {
return uri.with({
scheme: Schemas.vscodeFileResource,
// We need to provide an authority here so that it can serve
// as origin for network and loading matters in chromium.
// If the URI is not coming with an authority already, we
// add our own
authority: uri.authority || this.FALLBACK_AUTHORITY,
query: null,
fragment: null
});
}

/**
* Returns the `file` URI to use in contexts where node.js
* is responsible for loading.
Expand Down
20 changes: 20 additions & 0 deletions src/vs/base/common/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,26 @@ if (typeof process !== 'undefined') {

const isElectronRenderer = typeof nodeProcess?.versions?.electron === 'string' && nodeProcess.type === 'renderer';
export const isElectronSandboxed = isElectronRenderer && nodeProcess?.sandboxed;
export const browserCodeLoadingCacheStrategy: 'none' | 'code' | 'bypassHeatCheck' | 'bypassHeatCheckAndEagerCompile' | undefined = (() => {

// Always enabled when sandbox is enabled
if (isElectronSandboxed) {
return 'bypassHeatCheck';
}

// Otherwise, only enabled conditionally
const env = nodeProcess?.env['ENABLE_VSCODE_BROWSER_CODE_LOADING'];
if (typeof env === 'string') {
if (env === 'none' || env === 'code' || env === 'bypassHeatCheck' || env === 'bypassHeatCheckAndEagerCompile') {
return env;
}

return 'bypassHeatCheck';
}

return undefined;
})();
export const isPreferringBrowserCodeLoad = typeof browserCodeLoadingCacheStrategy === 'string';

// Web environment
if (typeof navigator === 'object' && !isElectronRenderer) {
Expand Down
4 changes: 2 additions & 2 deletions src/vs/base/test/common/network.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import * as assert from 'assert';
import { URI } from 'vs/base/common/uri';
import { FileAccess, Schemas } from 'vs/base/common/network';
import { isEqual } from 'vs/base/common/resources';
import { isElectronSandboxed } from 'vs/base/common/platform';
import { isPreferringBrowserCodeLoad } from 'vs/base/common/platform';

suite('network', () => {
const enableTest = isElectronSandboxed;
const enableTest = isPreferringBrowserCodeLoad;

(!enableTest ? test.skip : test)('FileAccess: URI (native)', () => {

Expand Down
10 changes: 6 additions & 4 deletions src/vs/code/electron-main/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { INativeEnvironmentService } from 'vs/platform/environment/common/enviro
import { session } from 'electron';
import { ILogService } from 'vs/platform/log/common/log';
import { TernarySearchTree } from 'vs/base/common/map';
import { isLinux } from 'vs/base/common/platform';
import { isLinux, isPreferringBrowserCodeLoad } from 'vs/base/common/platform';
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';

type ProtocolCallback = { (result: string | Electron.FilePathWithHeaders | { error: number }): void };
Expand All @@ -37,15 +37,17 @@ export class FileProtocolHandler extends Disposable {
// Register vscode-file:// handler
defaultSession.protocol.registerFileProtocol(Schemas.vscodeFileResource, (request, callback) => this.handleResourceRequest(request, callback as unknown as ProtocolCallback));

// Block any file:// access (sandbox only)
if (environmentService.args.__sandbox) {
// Block any file:// access (explicitly enabled only)
if (isPreferringBrowserCodeLoad) {
this.logService.info(`Intercepting ${Schemas.file}: protocol and blocking it`);

defaultSession.protocol.interceptFileProtocol(Schemas.file, (request, callback) => this.handleFileRequest(request, callback as unknown as ProtocolCallback));
}

// Cleanup
this._register(toDisposable(() => {
defaultSession.protocol.unregisterProtocol(Schemas.vscodeFileResource);
if (environmentService.args.__sandbox) {
if (isPreferringBrowserCodeLoad) {
defaultSession.protocol.uninterceptProtocol(Schemas.file);
}
}));
Expand Down
12 changes: 7 additions & 5 deletions src/vs/code/electron-main/sharedProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainServ
import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Event } from 'vs/base/common/event';
import { FileAccess } from 'vs/base/common/network';
import { browserCodeLoadingCacheStrategy } from 'vs/base/common/platform';

export class SharedProcess implements ISharedProcess {

Expand Down Expand Up @@ -41,6 +42,7 @@ export class SharedProcess implements ISharedProcess {
backgroundColor: this.themeMainService.getBackgroundColor(),
webPreferences: {
preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-browser/preload.js', require).fsPath,
v8CacheOptions: browserCodeLoadingCacheStrategy,
nodeIntegration: true,
enableWebSQL: false,
enableRemoteModule: false,
Expand All @@ -60,11 +62,11 @@ export class SharedProcess implements ISharedProcess {
windowId: this.window.id
};

const windowUrl = (this.environmentService.sandbox ?
FileAccess._asCodeFileUri('vs/code/electron-browser/sharedProcess/sharedProcess.html', require) :
FileAccess.asBrowserUri('vs/code/electron-browser/sharedProcess/sharedProcess.html', require))
.with({ query: `config=${encodeURIComponent(JSON.stringify(config))}` });
this.window.loadURL(windowUrl.toString(true));
this.window.loadURL(FileAccess
.asBrowserUri('vs/code/electron-browser/sharedProcess/sharedProcess.html', require)
.with({ query: `config=${encodeURIComponent(JSON.stringify(config))}` })
.toString(true)
);

// Prevent the window from dying
const onClose = (e: ElectronEvent) => {
Expand Down
15 changes: 10 additions & 5 deletions src/vs/code/electron-main/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
import product from 'vs/platform/product/common/product';
import { WindowMinimumSize, IWindowSettings, MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility, zoomLevelToZoomFactor, INativeWindowConfiguration } from 'vs/platform/windows/common/windows';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
import { browserCodeLoadingCacheStrategy, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
import { ICodeWindow, IWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows';
import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService';
Expand Down Expand Up @@ -164,6 +164,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
title: product.nameLong,
webPreferences: {
preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-browser/preload.js', require).fsPath,
v8CacheOptions: browserCodeLoadingCacheStrategy,
enableWebSQL: false,
enableRemoteModule: false,
spellcheck: false,
Expand All @@ -185,6 +186,10 @@ export class CodeWindow extends Disposable implements ICodeWindow {
}
};

if (browserCodeLoadingCacheStrategy) {
this.logService.info(`window#ctor: using vscode-file protocol and V8 cache options: ${browserCodeLoadingCacheStrategy}`);
}

// Apply icon to window
// Linux: always
// Windows: only when running out of sources, otherwise an icon is set by us on the executable
Expand Down Expand Up @@ -850,10 +855,10 @@ export class CodeWindow extends Disposable implements ICodeWindow {
workbench = 'vs/code/electron-browser/workbench/workbench.html';
}

return (this.environmentService.sandbox ?
FileAccess._asCodeFileUri(workbench, require) :
FileAccess.asBrowserUri(workbench, require))
.with({ query: `config=${encodeURIComponent(JSON.stringify(config))}` }).toString(true);
return FileAccess
.asBrowserUri(workbench, require)
.with({ query: `config=${encodeURIComponent(JSON.stringify(config))}` })
.toString(true);
}

serializeWindowState(): IWindowState {
Expand Down
4 changes: 3 additions & 1 deletion src/vs/platform/issue/electron-main/issueMainService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ export class IssueMainService implements ICommonIssueService {
backgroundColor: data.styles.backgroundColor || DEFAULT_BACKGROUND_COLOR,
webPreferences: {
preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-browser/preload.js', require).fsPath,
v8CacheOptions: 'bypassHeatCheck',
enableWebSQL: false,
enableRemoteModule: false,
spellcheck: false,
Expand Down Expand Up @@ -257,6 +258,7 @@ export class IssueMainService implements ICommonIssueService {
title: localize('processExplorer', "Process Explorer"),
webPreferences: {
preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-browser/preload.js', require).fsPath,
v8CacheOptions: 'bypassHeatCheck',
enableWebSQL: false,
enableRemoteModule: false,
spellcheck: false,
Expand Down Expand Up @@ -432,7 +434,7 @@ function toWindowUrl<T>(modulePathToHtml: string, windowConfiguration: T): strin
}

return FileAccess
._asCodeFileUri(modulePathToHtml, require)
.asBrowserUri(modulePathToHtml, require, true)
.with({ query: `config=${encodeURIComponent(JSON.stringify(config))}` })
.toString(true);
}

0 comments on commit 169a0ec

Please sign in to comment.