extract some COI handle into network-util, add --enable-coi command line flag and adopt in main handler

This commit is contained in:
Johannes
2022-09-02 12:21:10 +02:00
parent 653757b10d
commit 2aeb99b11d
9 changed files with 84 additions and 12 deletions

View File

@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { COI } from 'vs/base/common/network';
import { globals } from 'vs/base/common/platform'; import { globals } from 'vs/base/common/platform';
import { IWorker, IWorkerCallback, IWorkerFactory, logOnceWebWorkerWarning } from 'vs/base/common/worker/simpleWorker'; import { IWorker, IWorkerCallback, IWorkerFactory, logOnceWebWorkerWarning } from 'vs/base/common/worker/simpleWorker';
@@ -41,7 +42,12 @@ export function getWorkerBootstrapUrl(scriptPath: string, label: string): string
const blob = new Blob([js], { type: 'application/javascript' }); const blob = new Blob([js], { type: 'application/javascript' });
return URL.createObjectURL(blob); return URL.createObjectURL(blob);
} }
return scriptPath + '#' + label;
const result = new URL(scriptPath);
COI.addSearchParam(result.searchParams, true, true);
result.hash = label;
return result.href;
} }
// ESM-comment-end // ESM-comment-end

View File

@@ -251,3 +251,53 @@ class FileAccessImpl {
} }
export const FileAccess = new FileAccessImpl(); export const FileAccess = new FileAccessImpl();
export namespace COI {
const coiHeaders = new Map<'3' | '2' | '1' | string, Record<string, string>>([
['1', { 'Cross-Origin-Opener-Policy': 'same-origin' }],
['2', { 'Cross-Origin-Embedder-Policy': 'require-corp' }],
['3', { 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp' }],
]);
export const CoopAndCoep = Object.freeze(coiHeaders.get('3'));
const coiSearchParamName = 'vscode-coi';
/**
* Extract desired headers from `vscode-coi` invocation
*/
export function getHeadersFromQuery(url: string | URI | URL): Record<string, string> | undefined {
let params: URLSearchParams | undefined;
if (typeof url === 'string') {
params = new URL(url).searchParams;
} else if (url instanceof URL) {
params = url.searchParams;
} else if (URI.isUri(url)) {
params = new URL(url.toString(true)).searchParams;
}
const value = params?.get(coiSearchParamName);
if (!value) {
return undefined;
}
return coiHeaders.get(value);
}
/**
* Add the `vscode-coi` query attribute based on wanting `COOP` and `COEP`. Will be a noop when `crossOriginIsolated`
* isn't enabled the current context
*/
export function addSearchParam(urlOrSearch: URLSearchParams | Record<string, string>, coop: boolean, coep: boolean): void {
if (!globalThis.crossOriginIsolated) {
// depends on the current context being COI
return;
}
const value = coop && coep ? '3' : coep ? '2' : '1';
if (urlOrSearch instanceof URLSearchParams) {
urlOrSearch.set(coiSearchParamName, value);
} else {
(<Record<string, string>>urlOrSearch)[coiSearchParamName] = value;
}
}
}

View File

@@ -94,6 +94,8 @@ export interface NativeParsedArgs {
'profile'?: string; 'profile'?: string;
'profile-temp'?: boolean; 'profile-temp'?: boolean;
'enable-coi'?: boolean;
// chromium command line args: https://electronjs.org/docs/all#supported-chrome-command-line-switches // chromium command line args: https://electronjs.org/docs/all#supported-chrome-command-line-switches
'no-proxy-server'?: boolean; 'no-proxy-server'?: boolean;
'no-sandbox'?: boolean; 'no-sandbox'?: boolean;

View File

@@ -140,6 +140,8 @@ export interface INativeEnvironmentService extends IEnvironmentService {
// --- use keytar for credentials // --- use keytar for credentials
disableKeytar?: boolean; disableKeytar?: boolean;
crossOriginIsolated?: boolean;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// //
// NOTE: KEEP THIS INTERFACE AS SMALL AS POSSIBLE. // NOTE: KEEP THIS INTERFACE AS SMALL AS POSSIBLE.

View File

@@ -60,6 +60,9 @@ export class EnvironmentMainService extends NativeEnvironmentService implements
@memoize @memoize
get disableKeytar(): boolean { return !!this.args['disable-keytar']; } get disableKeytar(): boolean { return !!this.args['disable-keytar']; }
@memoize
get crossOriginIsolated(): boolean { return !!this.args['enable-coi']; }
@memoize @memoize
get codeCachePath(): string | undefined { return process.env['VSCODE_CODE_CACHE_PATH'] || undefined; } get codeCachePath(): string | undefined { return process.env['VSCODE_CODE_CACHE_PATH'] || undefined; }

View File

@@ -131,6 +131,8 @@ export const OPTIONS: OptionDescriptions<Required<NativeParsedArgs>> = {
'editSessionId': { type: 'string' }, 'editSessionId': { type: 'string' },
'locate-shell-integration-path': { type: 'string', args: ['bash', 'pwsh', 'zsh', 'fish'] }, 'locate-shell-integration-path': { type: 'string', args: ['bash', 'pwsh', 'zsh', 'fish'] },
'enable-coi': { type: 'boolean' },
// chromium flags // chromium flags
'no-proxy-server': { type: 'boolean' }, 'no-proxy-server': { type: 'boolean' },
// Minimist incorrectly parses keys that start with `--no` // Minimist incorrectly parses keys that start with `--no`

View File

@@ -7,7 +7,7 @@ import { session } from 'electron';
import { validatedIpcMain } from 'vs/base/parts/ipc/electron-main/ipcMain'; import { validatedIpcMain } from 'vs/base/parts/ipc/electron-main/ipcMain';
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { TernarySearchTree } from 'vs/base/common/map'; import { TernarySearchTree } from 'vs/base/common/map';
import { FileAccess, Schemas } from 'vs/base/common/network'; import { COI, FileAccess, Schemas } from 'vs/base/common/network';
import { extname, normalize } from 'vs/base/common/path'; import { extname, normalize } from 'vs/base/common/path';
import { isLinux } from 'vs/base/common/platform'; import { isLinux } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
@@ -27,7 +27,7 @@ export class ProtocolMainService extends Disposable implements IProtocolMainServ
private readonly validExtensions = new Set(['.svg', '.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp']); // https://github.com/microsoft/vscode/issues/119384 private readonly validExtensions = new Set(['.svg', '.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp']); // https://github.com/microsoft/vscode/issues/119384
constructor( constructor(
@INativeEnvironmentService environmentService: INativeEnvironmentService, @INativeEnvironmentService private readonly environmentService: INativeEnvironmentService,
@IUserDataProfilesService userDataProfilesService: IUserDataProfilesService, @IUserDataProfilesService userDataProfilesService: IUserDataProfilesService,
@ILogService private readonly logService: ILogService @ILogService private readonly logService: ILogService
) { ) {
@@ -94,9 +94,18 @@ export class ProtocolMainService extends Disposable implements IProtocolMainServ
private handleResourceRequest(request: Electron.ProtocolRequest, callback: ProtocolCallback): void { private handleResourceRequest(request: Electron.ProtocolRequest, callback: ProtocolCallback): void {
const path = this.requestToNormalizedFilePath(request); const path = this.requestToNormalizedFilePath(request);
let headers: Record<string, string> | undefined;
if (this.environmentService.crossOriginIsolated) {
if (path.endsWith('/workbench.html')) {
headers = COI.CoopAndCoep;
} else {
headers = COI.getHeadersFromQuery(request.url);
}
}
// first check by validRoots // first check by validRoots
if (this.validRoots.findSubstr(path)) { if (this.validRoots.findSubstr(path)) {
return callback({ path }); return callback({ path, headers });
} }
// then check by validExtensions // then check by validExtensions

View File

@@ -12,7 +12,7 @@ import { streamToBuffer, VSBufferReadableStream } from 'vs/base/common/buffer';
import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { Emitter, Event } from 'vs/base/common/event'; import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network'; import { COI, Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid'; import { generateUuid } from 'vs/base/common/uuid';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
@@ -532,9 +532,8 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD
params.purpose = options.purpose; params.purpose = options.purpose;
} }
if (globalThis.crossOriginIsolated) {
params['vscode-coi'] = '3'; /*COOP+COEP*/ COI.addSearchParam(params, true, true);
}
const queryString = new URLSearchParams(params).toString(); const queryString = new URLSearchParams(params).toString();

View File

@@ -27,7 +27,7 @@ import { generateUuid } from 'vs/base/common/uuid';
import { canceled, onUnexpectedError } from 'vs/base/common/errors'; import { canceled, onUnexpectedError } from 'vs/base/common/errors';
import { Barrier } from 'vs/base/common/async'; import { Barrier } from 'vs/base/common/async';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { FileAccess } from 'vs/base/common/network'; import { COI, FileAccess } from 'vs/base/common/network';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { parentOriginHash } from 'vs/workbench/browser/webview'; import { parentOriginHash } from 'vs/workbench/browser/webview';
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
@@ -86,9 +86,8 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
if (this._environmentService.debugExtensionHost && this._environmentService.debugRenderer) { if (this._environmentService.debugExtensionHost && this._environmentService.debugRenderer) {
suffixSearchParams.set('debugged', '1'); suffixSearchParams.set('debugged', '1');
} }
if (globalThis.crossOriginIsolated) { COI.addSearchParam(suffixSearchParams, true, true);
suffixSearchParams.set('vscode-coi', '3' /*COOP+COEP*/);
}
const suffix = `?${suffixSearchParams.toString()}`; const suffix = `?${suffixSearchParams.toString()}`;
const iframeModulePath = 'vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html'; const iframeModulePath = 'vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html';