@sussudio/platform
Version:
Internal APIs for VS Code's service injection the base services.
159 lines (158 loc) • 6.56 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var __decorate =
(this && this.__decorate) ||
function (decorators, target, key, desc) {
var c = arguments.length,
r = c < 3 ? target : desc === null ? (desc = Object.getOwnPropertyDescriptor(target, key)) : desc,
d;
if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function')
r = Reflect.decorate(decorators, target, key, desc);
else
for (var i = decorators.length - 1; i >= 0; i--)
if ((d = decorators[i])) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param =
(this && this.__param) ||
function (paramIndex, decorator) {
return function (target, key) {
decorator(target, key, paramIndex);
};
};
import { session } from 'electron';
import { Disposable, toDisposable } from '@sussudio/base/common/lifecycle.mjs';
import { COI, FileAccess, Schemas } from '@sussudio/base/common/network.mjs';
import { basename, extname, normalize } from '@sussudio/base/common/path.mjs';
import { isLinux } from '@sussudio/base/common/platform.mjs';
import { TernarySearchTree } from '@sussudio/base/common/ternarySearchTree.mjs';
import { URI } from '@sussudio/base/common/uri.mjs';
import { generateUuid } from '@sussudio/base/common/uuid.mjs';
import { validatedIpcMain } from '@sussudio/base/parts/ipc/electron-main/ipcMain.mjs';
import { INativeEnvironmentService } from '../../environment/common/environment.mjs';
import { ILogService } from '../../log/common/log.mjs';
import { IUserDataProfilesService } from '../../userDataProfile/common/userDataProfile.mjs';
let ProtocolMainService = class ProtocolMainService extends Disposable {
environmentService;
logService;
validRoots = TernarySearchTree.forPaths(!isLinux);
validExtensions = new Set(['.svg', '.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp']); // https://github.com/microsoft/vscode/issues/119384
constructor(environmentService, userDataProfilesService, logService) {
super();
this.environmentService = environmentService;
this.logService = logService;
// Define an initial set of roots we allow loading from
// - appRoot : all files installed as part of the app
// - extensions : all files shipped from extensions
// - storage : all files in global and workspace storage (https://github.com/microsoft/vscode/issues/116735)
this.addValidFileRoot(environmentService.appRoot);
this.addValidFileRoot(environmentService.extensionsPath);
this.addValidFileRoot(userDataProfilesService.defaultProfile.globalStorageHome.fsPath);
this.addValidFileRoot(environmentService.workspaceStorageHome.fsPath);
// Handle protocols
this.handleProtocols();
}
handleProtocols() {
const { defaultSession } = session;
// Register vscode-file:// handler
defaultSession.protocol.registerFileProtocol(Schemas.vscodeFileResource, (request, callback) =>
this.handleResourceRequest(request, callback),
);
// Block any file:// access
defaultSession.protocol.interceptFileProtocol(Schemas.file, (request, callback) =>
this.handleFileRequest(request, callback),
);
// Cleanup
this._register(
toDisposable(() => {
defaultSession.protocol.unregisterProtocol(Schemas.vscodeFileResource);
defaultSession.protocol.uninterceptProtocol(Schemas.file);
}),
);
}
addValidFileRoot(root) {
// Pass to `normalize` because we later also do the
// same for all paths to check against.
const normalizedRoot = normalize(root);
if (!this.validRoots.get(normalizedRoot)) {
this.validRoots.set(normalizedRoot, true);
return toDisposable(() => this.validRoots.delete(normalizedRoot));
}
return Disposable.None;
}
//#region file://
handleFileRequest(request, callback) {
const uri = URI.parse(request.url);
this.logService.error(
`Refused to load resource ${uri.fsPath} from ${Schemas.file}: protocol (original URL: ${request.url})`,
);
return callback({ error: -3 /* ABORTED */ });
}
//#endregion
//#region vscode-file://
handleResourceRequest(request, callback) {
const path = this.requestToNormalizedFilePath(request);
let headers;
if (this.environmentService.crossOriginIsolated) {
if (basename(path) === 'workbench.html' || basename(path) === 'workbench-dev.html') {
headers = COI.CoopAndCoep;
} else {
headers = COI.getHeadersFromQuery(request.url);
}
}
// first check by validRoots
if (this.validRoots.findSubstr(path)) {
return callback({ path, headers });
}
// then check by validExtensions
if (this.validExtensions.has(extname(path).toLowerCase())) {
return callback({ path });
}
// finally block to load the resource
this.logService.error(
`${Schemas.vscodeFileResource}: Refused to load resource ${path} from ${Schemas.vscodeFileResource}: protocol (original URL: ${request.url})`,
);
return callback({ error: -3 /* ABORTED */ });
}
requestToNormalizedFilePath(request) {
// 1.) Use `URI.parse()` util from us to convert the raw
// URL into our URI.
const requestUri = URI.parse(request.url);
// 2.) Use `FileAccess.asFileUri` to convert back from a
// `vscode-file:` URI to a `file:` URI.
const unnormalizedFileUri = FileAccess.uriToFileUri(requestUri);
// 3.) Strip anything from the URI that could result in
// relative paths (such as "..") by using `normalize`
return normalize(unnormalizedFileUri.fsPath);
}
//#endregion
//#region IPC Object URLs
createIPCObjectUrl() {
let obj = undefined;
// Create unique URI
const resource = URI.from({
scheme: 'vscode',
path: generateUuid(),
});
// Install IPC handler
const channel = resource.toString();
const handler = async () => obj;
validatedIpcMain.handle(channel, handler);
this.logService.trace(`IPC Object URL: Registered new channel ${channel}.`);
return {
resource,
update: (updatedObj) => (obj = updatedObj),
dispose: () => {
this.logService.trace(`IPC Object URL: Removed channel ${channel}.`);
validatedIpcMain.removeHandler(channel);
},
};
}
};
ProtocolMainService = __decorate(
[__param(0, INativeEnvironmentService), __param(1, IUserDataProfilesService), __param(2, ILogService)],
ProtocolMainService,
);
export { ProtocolMainService };