未验证 提交 14415847 编写于 作者: J João Moreno

trusted extension urls

上级 2cd7a70d
......@@ -88,6 +88,9 @@ import { DisplayMainService, IDisplayMainService } from 'vs/platform/display/ele
import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper';
import { isEqualOrParent } from 'vs/base/common/extpath';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { IExtensionUrlTrustService } from 'vs/platform/extensionManagement/common/extensionUrlTrust';
import { ExtensionUrlTrustChannel } from 'vs/platform/extensionManagement/common/extensionUrlTrustIpc';
import { ExtensionUrlTrustService } from 'vs/platform/extensionManagement/node/extensionUrlTrustService';
export class CodeApplication extends Disposable {
private windowsMainService: IWindowsMainService | undefined;
......@@ -520,6 +523,7 @@ export class CodeApplication extends Disposable {
services.set(IWebviewManagerService, new SyncDescriptor(WebviewMainService));
services.set(IWorkspacesService, new SyncDescriptor(WorkspacesService));
services.set(IMenubarMainService, new SyncDescriptor(MenubarMainService));
services.set(IExtensionUrlTrustService, new SyncDescriptor(ExtensionUrlTrustService));
const storageMainService = new StorageMainService(this.logService, this.environmentService);
services.set(IStorageMainService, storageMainService);
......@@ -635,6 +639,10 @@ export class CodeApplication extends Disposable {
const urlChannel = createChannelReceiver(urlService);
electronIpcServer.registerChannel('url', urlChannel);
const extensionUrlTrustService = accessor.get(IExtensionUrlTrustService);
const extensionUrlTrustChannel = new ExtensionUrlTrustChannel(extensionUrlTrustService);
electronIpcServer.registerChannel('extensionUrlTrust', extensionUrlTrustChannel);
const webviewManagerService = accessor.get(IWebviewManagerService);
const webviewChannel = createChannelReceiver(webviewManagerService);
electronIpcServer.registerChannel('webview', webviewChannel);
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
export const IExtensionUrlTrustService = createDecorator<IExtensionUrlTrustService>('extensionUrlTrustService');
export interface IExtensionUrlTrustService {
readonly _serviceBrand: undefined;
isExtensionUrlTrusted(extensionId: string, url: string): Promise<boolean>;
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { Event } from 'vs/base/common/event';
import { IExtensionUrlTrustService } from 'vs/platform/extensionManagement/common/extensionUrlTrust';
export class ExtensionUrlTrustChannel implements IServerChannel {
constructor(private service: IExtensionUrlTrustService) { }
listen(): Event<any> {
throw new Error('No events supported');
}
call(_: any, command: string, arg?: any): Promise<any> {
switch (command) {
case 'isExtensionUrlTrusted': return this.service.isExtensionUrlTrusted(arg[0], arg[1]);
}
throw new Error('Invalid call');
}
}
export class ExtensionUrlTrustChannelClient implements IExtensionUrlTrustService {
declare readonly _serviceBrand: undefined;
constructor(private readonly channel: IChannel) { }
isExtensionUrlTrusted(extensionId: string, url: string): Promise<boolean> {
return this.channel.call('isExtensionUrlTrusted', [extensionId, url]);
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as crypto from 'crypto';
import { IExtensionUrlTrustService } from 'vs/platform/extensionManagement/common/extensionUrlTrust';
import { ILogService } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';
export class ExtensionUrlTrustService implements IExtensionUrlTrustService {
declare readonly _serviceBrand: undefined;
private trustedExtensionUrlPublicKeys = new Map<string, (crypto.KeyObject | string | null)[]>();
constructor(
@IProductService private readonly productService: IProductService,
@ILogService private readonly logService: ILogService
) { }
async isExtensionUrlTrusted(extensionId: string, url: string): Promise<boolean> {
if (!this.productService.trustedExtensionUrlPublicKeys) {
this.logService.trace('ExtensionUrlTrustService#isExtensionUrlTrusted', 'There are no configured trusted keys');
return false;
}
const match = /^(.*)#([^#]+)$/.exec(url);
if (!match) {
this.logService.trace('ExtensionUrlTrustService#isExtensionUrlTrusted', 'Uri has no fragment', url);
return false;
}
const [, originalUrl, fragment] = match;
let keys = this.trustedExtensionUrlPublicKeys.get(extensionId);
if (!keys) {
keys = this.productService.trustedExtensionUrlPublicKeys[extensionId];
if (!keys || keys.length === 0) {
this.logService.trace('ExtensionUrlTrustService#isExtensionUrlTrusted', 'Extension doesn\'t have any trusted keys', extensionId);
return false;
}
this.trustedExtensionUrlPublicKeys.set(extensionId, [...keys]);
}
const fragmentBuffer = Buffer.from(decodeURIComponent(fragment), 'base64');
if (fragmentBuffer.length <= 6) {
this.logService.trace('ExtensionUrlTrustService#isExtensionUrlTrusted', 'Uri fragment is not a signature', url);
return false;
}
const timestampBuffer = fragmentBuffer.slice(0, 6);
const timestamp = fragmentBuffer.readUIntBE(0, 6);
const diff = Date.now() - timestamp;
if (diff < 0 || diff > 600_000) { // 10 minutes
this.logService.trace('ExtensionUrlTrustService#isExtensionUrlTrusted', 'Signed uri has expired', url);
return false;
}
const signatureBuffer = fragmentBuffer.slice(6);
const verify = crypto.createVerify('SHA256');
verify.write(timestampBuffer);
verify.write(Buffer.from(originalUrl));
verify.end();
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
if (key === null) { // failed to be parsed before
continue;
} else if (typeof key === 'string') { // needs to be parsed
try {
key = crypto.createPublicKey({ key: Buffer.from(key, 'base64'), format: 'der', type: 'spki' });
keys[i] = key;
} catch (err) {
this.logService.warn('ExtensionUrlTrustService#isExtensionUrlTrusted', `Failed to parse trusted extension uri public key #${i + 1} for ${extensionId}:`, err);
keys[i] = null;
continue;
}
}
if (verify.verify(key, signatureBuffer)) {
this.logService.trace('ExtensionUrlTrustService#isExtensionUrlTrusted', 'Signed uri is valid', url);
return true;
}
}
this.logService.trace('ExtensionUrlTrustService#isExtensionUrlTrusted', 'Signed uri could not be verified', url);
return false;
}
}
......@@ -80,6 +80,7 @@ export interface IProductConfiguration {
readonly remoteExtensionTips?: { [remoteName: string]: IRemoteExtensionTip; };
readonly extensionKeywords?: { [extension: string]: readonly string[]; };
readonly keymapExtensionTips?: readonly string[];
readonly trustedExtensionUrlPublicKeys?: { [id: string]: string[]; };
readonly crashReporter?: {
readonly companyName: string;
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IExtensionUrlTrustService } from 'vs/platform/extensionManagement/common/extensionUrlTrust';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
class ExtensionUrlTrustService implements IExtensionUrlTrustService {
declare readonly _serviceBrand: undefined;
async isExtensionUrlTrusted(): Promise<boolean> {
return false;
}
}
registerSingleton(IExtensionUrlTrustService, ExtensionUrlTrustService);
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IExtensionUrlTrustService } from 'vs/platform/extensionManagement/common/extensionUrlTrust';
import { ExtensionUrlTrustChannelClient } from 'vs/platform/extensionManagement/common/extensionUrlTrustIpc';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
class ExtensionUrlTrustService extends ExtensionUrlTrustChannelClient {
declare readonly _serviceBrand: undefined;
constructor(@IMainProcessService mainProcessService: IMainProcessService) {
super(mainProcessService.getChannel('extensionUrlTrust'));
}
}
registerSingleton(IExtensionUrlTrustService, ExtensionUrlTrustService);
......@@ -26,6 +26,7 @@ import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/act
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys';
import { IExtensionUrlTrustService } from 'vs/platform/extensionManagement/common/extensionUrlTrust';
const FIVE_MINUTES = 5 * 60 * 1000;
const THIRTY_SECONDS = 30 * 1000;
......@@ -101,7 +102,8 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
@IExtensionGalleryService private readonly galleryService: IExtensionGalleryService,
@IStorageService private readonly storageService: IStorageService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IProgressService private readonly progressService: IProgressService
@IProgressService private readonly progressService: IProgressService,
@IExtensionUrlTrustService private readonly extensionUrlTrustService: IExtensionUrlTrustService
) {
this.userTrustedExtensionsStorage = new UserTrustedExtensionIdStorage(storageService);
......@@ -135,11 +137,9 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
return true;
}
let trusted = options?.trusted;
if (!trusted) {
trusted = this.didUserTrustExtension(ExtensionIdentifier.toKey(extensionId));
}
const trusted = options?.trusted
|| (options?.originalUrl ? await this.extensionUrlTrustService.isExtensionUrlTrusted(extensionId, options.originalUrl) : false)
|| this.didUserTrustExtension(ExtensionIdentifier.toKey(extensionId));
if (!trusted) {
let uriString = uri.toString(false);
......
......@@ -46,6 +46,7 @@ import 'vs/workbench/services/accessibility/electron-sandbox/accessibilityServic
import 'vs/workbench/services/path/electron-sandbox/pathService';
import 'vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService';
import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService';
import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionUrlTrustService';
import 'vs/workbench/services/credentials/electron-sandbox/credentialsService';
import 'vs/workbench/services/encryption/electron-sandbox/encryptionService';
......
......@@ -41,6 +41,7 @@ import 'vs/workbench/services/textfile/browser/browserTextFileService';
import 'vs/workbench/services/keybinding/browser/keyboardLayoutService';
import 'vs/workbench/services/extensions/browser/extensionService';
import 'vs/workbench/services/extensionManagement/common/extensionManagementServerService';
import 'vs/workbench/services/extensionManagement/browser/extensionUrlTrustService';
import 'vs/workbench/services/telemetry/browser/telemetryService';
import 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
import 'vs/workbench/services/credentials/browser/credentialsService';
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册