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
+7 -1
View File
@@ -3,6 +3,7 @@
* 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 { 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' });
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
+50
View File
@@ -251,3 +251,53 @@ class 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;
}
}
}
@@ -94,6 +94,8 @@ export interface NativeParsedArgs {
'profile'?: string;
'profile-temp'?: boolean;
'enable-coi'?: boolean;
// chromium command line args: https://electronjs.org/docs/all#supported-chrome-command-line-switches
'no-proxy-server'?: boolean;
'no-sandbox'?: boolean;
@@ -140,6 +140,8 @@ export interface INativeEnvironmentService extends IEnvironmentService {
// --- use keytar for credentials
disableKeytar?: boolean;
crossOriginIsolated?: boolean;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// NOTE: KEEP THIS INTERFACE AS SMALL AS POSSIBLE.
@@ -60,6 +60,9 @@ export class EnvironmentMainService extends NativeEnvironmentService implements
@memoize
get disableKeytar(): boolean { return !!this.args['disable-keytar']; }
@memoize
get crossOriginIsolated(): boolean { return !!this.args['enable-coi']; }
@memoize
get codeCachePath(): string | undefined { return process.env['VSCODE_CODE_CACHE_PATH'] || undefined; }
+2
View File
@@ -131,6 +131,8 @@ export const OPTIONS: OptionDescriptions<Required<NativeParsedArgs>> = {
'editSessionId': { type: 'string' },
'locate-shell-integration-path': { type: 'string', args: ['bash', 'pwsh', 'zsh', 'fish'] },
'enable-coi': { type: 'boolean' },
// chromium flags
'no-proxy-server': { type: 'boolean' },
// Minimist incorrectly parses keys that start with `--no`
@@ -7,7 +7,7 @@ import { session } from 'electron';
import { validatedIpcMain } from 'vs/base/parts/ipc/electron-main/ipcMain';
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
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 { isLinux } from 'vs/base/common/platform';
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
constructor(
@INativeEnvironmentService environmentService: INativeEnvironmentService,
@INativeEnvironmentService private readonly environmentService: INativeEnvironmentService,
@IUserDataProfilesService userDataProfilesService: IUserDataProfilesService,
@ILogService private readonly logService: ILogService
) {
@@ -94,9 +94,18 @@ export class ProtocolMainService extends Disposable implements IProtocolMainServ
private handleResourceRequest(request: Electron.ProtocolRequest, callback: ProtocolCallback): void {
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
if (this.validRoots.findSubstr(path)) {
return callback({ path });
return callback({ path, headers });
}
// then check by validExtensions
@@ -12,7 +12,7 @@ import { streamToBuffer, VSBufferReadableStream } from 'vs/base/common/buffer';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { Emitter, Event } from 'vs/base/common/event';
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 { generateUuid } from 'vs/base/common/uuid';
import { localize } from 'vs/nls';
@@ -532,9 +532,8 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD
params.purpose = options.purpose;
}
if (globalThis.crossOriginIsolated) {
params['vscode-coi'] = '3'; /*COOP+COEP*/
}
COI.addSearchParam(params, true, true);
const queryString = new URLSearchParams(params).toString();
@@ -27,7 +27,7 @@ import { generateUuid } from 'vs/base/common/uuid';
import { canceled, onUnexpectedError } from 'vs/base/common/errors';
import { Barrier } from 'vs/base/common/async';
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 { parentOriginHash } from 'vs/workbench/browser/webview';
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) {
suffixSearchParams.set('debugged', '1');
}
if (globalThis.crossOriginIsolated) {
suffixSearchParams.set('vscode-coi', '3' /*COOP+COEP*/);
}
COI.addSearchParam(suffixSearchParams, true, true);
const suffix = `?${suffixSearchParams.toString()}`;
const iframeModulePath = 'vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html';