Skip to content

Commit dc8f291

Browse files
author
Benjamin Pasero
committed
sandbox - let workspaces service use sandboxed IPC
1 parent c3c1a95 commit dc8f291

20 files changed

Lines changed: 273 additions & 167 deletions

File tree

.eslintrc.json

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,54 @@
761761
"*" // node modules
762762
]
763763
},
764+
{
765+
"target": "**/src/vs/workbench/workbench.common.main.ts",
766+
"restrictions": [
767+
"vs/nls",
768+
"**/vs/base/**/{common,browser}/**",
769+
"**/vs/base/parts/**/{common,browser}/**",
770+
"**/vs/platform/**/{common,browser}/**",
771+
"**/vs/editor/**",
772+
"**/vs/workbench/**/{common,browser}/**"
773+
]
774+
},
775+
{
776+
"target": "**/src/vs/workbench/workbench.web.main.ts",
777+
"restrictions": [
778+
"vs/nls",
779+
"**/vs/base/**/{common,browser}/**",
780+
"**/vs/base/parts/**/{common,browser}/**",
781+
"**/vs/platform/**/{common,browser}/**",
782+
"**/vs/editor/**",
783+
"**/vs/workbench/**/{common,browser}/**",
784+
"**/vs/workbench/workbench.common.main"
785+
]
786+
},
787+
{
788+
"target": "**/src/vs/workbench/workbench.sandbox.main.ts",
789+
"restrictions": [
790+
"vs/nls",
791+
"**/vs/base/**/{common,browser,electron-sandbox}/**",
792+
"**/vs/base/parts/**/{common,browser,electron-sandbox}/**",
793+
"**/vs/platform/**/{common,browser,electron-sandbox}/**",
794+
"**/vs/editor/**",
795+
"**/vs/workbench/**/{common,browser,electron-sandbox}/**",
796+
"**/vs/workbench/workbench.common.main"
797+
]
798+
},
799+
{
800+
"target": "**/src/vs/workbench/workbench.desktop.main.ts",
801+
"restrictions": [
802+
"vs/nls",
803+
"**/vs/base/**/{common,browser,node,electron-sandbox,electron-browser}/**",
804+
"**/vs/base/parts/**/{common,browser,node,electron-sandbox,electron-browser}/**",
805+
"**/vs/platform/**/{common,browser,node,electron-sandbox,electron-browser}/**",
806+
"**/vs/editor/**",
807+
"**/vs/workbench/**/{common,browser,node,electron-sandbox,electron-browser}/**",
808+
"**/vs/workbench/workbench.common.main",
809+
"**/vs/workbench/workbench.sandbox.main"
810+
]
811+
},
764812
{
765813
"target": "**/extensions/**",
766814
"restrictions": "**/*"

src/vs/base/parts/ipc/common/ipc.ts

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cance
1010
import * as errors from 'vs/base/common/errors';
1111
import { VSBuffer } from 'vs/base/common/buffer';
1212
import { getRandomElement } from 'vs/base/common/arrays';
13-
import { isFunction } from 'vs/base/common/types';
13+
import { isFunction, isUndefinedOrNull } from 'vs/base/common/types';
14+
import { revive } from 'vs/base/common/marshalling';
15+
import { isUpperAsciiLetter } from 'vs/base/common/strings';
1416

1517
/**
1618
* An `IChannel` is an abstraction over a collection of commands.
@@ -919,3 +921,131 @@ export class StaticRouter<TContext = string> implements IClientRouter<TContext>
919921
return await this.route(hub);
920922
}
921923
}
924+
925+
926+
//#region createChannelReceiver / createChannelSender
927+
928+
/**
929+
* Use both `createChannelReceiver` and `createChannelSender`
930+
* for automated process <=> process communication over methods
931+
* and events. You do not need to spell out each method on both
932+
* sides, a proxy will take care of this.
933+
*
934+
* Rules:
935+
* - if marshalling is enabled, only `URI` and `RegExp` is converted
936+
* automatically for you
937+
* - events must follow the naming convention `onUppercase`
938+
* - `CancellationToken` is currently not supported
939+
* - if a context is provided, you can use `AddFirstParameterToFunctions`
940+
* utility to signal this in the receiving side type
941+
*/
942+
943+
export interface IBaseChannelOptions {
944+
945+
/**
946+
* Disables automatic marshalling of `URI`.
947+
* If marshalling is disabled, `UriComponents`
948+
* must be used instead.
949+
*/
950+
disableMarshalling?: boolean;
951+
}
952+
953+
export interface IChannelReceiverOptions extends IBaseChannelOptions { }
954+
955+
export function createChannelReceiver(service: unknown, options?: IChannelReceiverOptions): IServerChannel {
956+
const handler = service as { [key: string]: unknown };
957+
const disableMarshalling = options && options.disableMarshalling;
958+
959+
// Buffer any event that should be supported by
960+
// iterating over all property keys and finding them
961+
const mapEventNameToEvent = new Map<string, Event<unknown>>();
962+
for (const key in handler) {
963+
if (propertyIsEvent(key)) {
964+
mapEventNameToEvent.set(key, Event.buffer(handler[key] as Event<unknown>, true));
965+
}
966+
}
967+
968+
return new class implements IServerChannel {
969+
970+
listen<T>(_: unknown, event: string): Event<T> {
971+
const eventImpl = mapEventNameToEvent.get(event);
972+
if (eventImpl) {
973+
return eventImpl as Event<T>;
974+
}
975+
976+
throw new Error(`Event not found: ${event}`);
977+
}
978+
979+
call(_: unknown, command: string, args?: any[]): Promise<any> {
980+
const target = handler[command];
981+
if (typeof target === 'function') {
982+
983+
// Revive unless marshalling disabled
984+
if (!disableMarshalling && Array.isArray(args)) {
985+
for (let i = 0; i < args.length; i++) {
986+
args[i] = revive(args[i]);
987+
}
988+
}
989+
990+
return target.apply(handler, args);
991+
}
992+
993+
throw new Error(`Method not found: ${command}`);
994+
}
995+
};
996+
}
997+
998+
export interface IChannelSenderOptions extends IBaseChannelOptions {
999+
1000+
/**
1001+
* If provided, will add the value of `context`
1002+
* to each method call to the target.
1003+
*/
1004+
context?: unknown;
1005+
}
1006+
1007+
export function createChannelSender<T>(channel: IChannel, options?: IChannelSenderOptions): T {
1008+
const disableMarshalling = options && options.disableMarshalling;
1009+
1010+
return new Proxy({}, {
1011+
get(_target: T, propKey: PropertyKey) {
1012+
if (typeof propKey === 'string') {
1013+
1014+
// Event
1015+
if (propertyIsEvent(propKey)) {
1016+
return channel.listen(propKey);
1017+
}
1018+
1019+
// Function
1020+
return async function (...args: any[]) {
1021+
1022+
// Add context if any
1023+
let methodArgs: any[];
1024+
if (options && !isUndefinedOrNull(options.context)) {
1025+
methodArgs = [options.context, ...args];
1026+
} else {
1027+
methodArgs = args;
1028+
}
1029+
1030+
const result = await channel.call(propKey, methodArgs);
1031+
1032+
// Revive unless marshalling disabled
1033+
if (!disableMarshalling) {
1034+
return revive(result);
1035+
}
1036+
1037+
return result;
1038+
};
1039+
}
1040+
1041+
throw new Error(`Property not found: ${String(propKey)}`);
1042+
}
1043+
}) as T;
1044+
}
1045+
1046+
function propertyIsEvent(name: string): boolean {
1047+
// Assume a property is an event if it has a form of "onSomething"
1048+
return name[0] === 'o' && name[1] === 'n' && isUpperAsciiLetter(name.charCodeAt(2));
1049+
}
1050+
1051+
//#endregion

src/vs/base/parts/ipc/node/ipc.ts

Lines changed: 0 additions & 133 deletions
This file was deleted.

src/vs/base/parts/ipc/test/node/ipc.test.ts renamed to src/vs/base/parts/ipc/test/common/ipc.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as assert from 'assert';
7-
import { IChannel, IServerChannel, IMessagePassingProtocol, IPCServer, ClientConnectionEvent, IPCClient } from 'vs/base/parts/ipc/common/ipc';
8-
import { createChannelReceiver, createChannelSender } from 'vs/base/parts/ipc/node/ipc';
7+
import { IChannel, IServerChannel, IMessagePassingProtocol, IPCServer, ClientConnectionEvent, IPCClient, createChannelReceiver, createChannelSender } from 'vs/base/parts/ipc/common/ipc';
98
import { Emitter, Event } from 'vs/base/common/event';
109
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
1110
import { canceled } from 'vs/base/common/errors';

src/vs/code/electron-browser/issue/issueReporterMain.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ import { debounce } from 'vs/base/common/decorators';
1515
import { Disposable } from 'vs/base/common/lifecycle';
1616
import * as platform from 'vs/base/common/platform';
1717
import { escape } from 'vs/base/common/strings';
18-
import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
19-
import { createChannelSender } from 'vs/base/parts/ipc/node/ipc';
18+
import { getDelayedChannel, createChannelSender } from 'vs/base/parts/ipc/common/ipc';
2019
import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net';
2120
import { normalizeGitHubUrl } from 'vs/platform/issue/common/issueReporterUtil';
2221
import { IssueReporterData as IssueReporterModelData, IssueReporterModel } from 'vs/code/electron-browser/issue/issueReporterModel';

src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ import { ILocalizationsService } from 'vs/platform/localizations/common/localiza
3535
import { combinedDisposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
3636
import { DownloadService } from 'vs/platform/download/common/downloadService';
3737
import { IDownloadService } from 'vs/platform/download/common/download';
38-
import { IChannel, IServerChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc';
39-
import { createChannelSender, createChannelReceiver } from 'vs/base/parts/ipc/node/ipc';
38+
import { IChannel, IServerChannel, StaticRouter, createChannelSender, createChannelReceiver } from 'vs/base/parts/ipc/common/ipc';
4039
import { NodeCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner';
4140
import { LanguagePackCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner';
4241
import { StorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner';

src/vs/code/electron-browser/workbench/preload.js

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,6 @@
99

1010
const { ipcRenderer } = require('electron');
1111

12-
/**
13-
* @param {string} channel
14-
*/
15-
function validateIPC(channel) {
16-
if (!channel || !channel.startsWith('vscode:')) {
17-
throw new Error(`Unsupported event IPC channel '${channel}'`);
18-
}
19-
}
20-
2112
// @ts-ignore
2213
window.vscode = {
2314

@@ -58,4 +49,17 @@
5849
}
5950
}
6051
};
52+
53+
//#region Utilities
54+
55+
/**
56+
* @param {string} channel
57+
*/
58+
function validateIPC(channel) {
59+
if (!channel || !channel.startsWith('vscode:')) {
60+
throw new Error(`Unsupported event IPC channel '${channel}'`);
61+
}
62+
}
63+
64+
//#endregion
6165
}());

0 commit comments

Comments
 (0)