mirror of
https://github.com/Microsoft/vscode
synced 2024-10-04 02:14:06 +00:00
sandbox - allow to enable vscode-file protocol via argv or environment (#98682)
This commit is contained in:
parent
b1659198f6
commit
169a0ec047
9
src/bootstrap-window.js
vendored
9
src/bootstrap-window.js
vendored
|
@ -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
|
||||
|
@ -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:
|
||||
|
|
31
src/main.js
31
src/main.js
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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`
|
||||
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)', () => {
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
@ -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);
|
||||
}
|
||||
}));
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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) => {
|
||||
|
|
|
@ -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';
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue