Introduce trustedExtensionProtocolHandlers (#194304)

* remove url

* use trustedExtensionProtocolHandlers
This commit is contained in:
João Moreno 2023-09-27 15:35:55 +01:00 committed by GitHub
parent 3ff4f98cdd
commit 45358184ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 6 additions and 153 deletions

View file

@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.83.0",
"distro": "7181d0c2e9094f4f9f90764e81ebac2443072cb7",
"distro": "e61050c5d43d2c66a196fafaa2b78d4f2a8c929a",
"author": {
"name": "Microsoft Corporation"
},
@ -231,4 +231,4 @@
"optionalDependencies": {
"windows-foreground-love": "0.5.0"
}
}
}

View file

@ -114,6 +114,7 @@ export interface IProductConfiguration {
readonly languageExtensionTips?: readonly string[];
readonly trustedExtensionUrlPublicKeys?: IStringDictionary<string[]>;
readonly trustedExtensionAuthAccess?: readonly string[];
readonly trustedExtensionProtocolHandlers?: readonly string[];
readonly commandPaletteSuggestedCommandIds?: string[];

View file

@ -41,8 +41,6 @@ import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper';
import { getResolvedShellEnv } from 'vs/platform/shell/node/shellEnv';
import { IExtensionUrlTrustService } from 'vs/platform/extensionManagement/common/extensionUrlTrust';
import { ExtensionUrlTrustService } from 'vs/platform/extensionManagement/node/extensionUrlTrustService';
import { IExtensionHostStarter, ipcExtensionHostStarterChannelName } from 'vs/platform/extensions/common/extensionHostStarter';
import { ExtensionHostStarter } from 'vs/platform/extensions/electron-main/extensionHostStarter';
import { IExternalTerminalMainService } from 'vs/platform/externalTerminal/electron-main/externalTerminal';
@ -968,9 +966,6 @@ export class CodeApplication extends Disposable {
// Menubar
services.set(IMenubarMainService, new SyncDescriptor(MenubarMainService));
// Extension URL Trust
services.set(IExtensionUrlTrustService, new SyncDescriptor(ExtensionUrlTrustService));
// Extension Host Starter
services.set(IExtensionHostStarter, new SyncDescriptor(ExtensionHostStarter));
@ -1118,10 +1113,6 @@ export class CodeApplication extends Disposable {
const urlChannel = ProxyChannel.fromService(accessor.get(IURLService), disposables);
mainProcessElectronServer.registerChannel('url', urlChannel);
// Extension URL Trust
const extensionUrlTrustChannel = ProxyChannel.fromService(accessor.get(IExtensionUrlTrustService), disposables);
mainProcessElectronServer.registerChannel('extensionUrlTrust', extensionUrlTrustChannel);
// Webview Manager
const webviewChannel = ProxyChannel.fromService(accessor.get(IWebviewManagerService), disposables);
mainProcessElectronServer.registerChannel('webview', webviewChannel);

View file

@ -1,13 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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>;
}

View file

@ -1,97 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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 > 3_600_000) { // 1 hour
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;
}
}

View file

@ -1,18 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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 { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
class ExtensionUrlTrustService implements IExtensionUrlTrustService {
declare readonly _serviceBrand: undefined;
async isExtensionUrlTrusted(): Promise<boolean> {
return false;
}
}
registerSingleton(IExtensionUrlTrustService, ExtensionUrlTrustService, InstantiationType.Delayed);

View file

@ -1,9 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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 { registerMainProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services';
registerMainProcessRemoteService(IExtensionUrlTrustService, 'extensionUrlTrust');

View file

@ -26,10 +26,10 @@ 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';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IProductService } from 'vs/platform/product/common/productService';
const FIVE_MINUTES = 5 * 60 * 1000;
const THIRTY_SECONDS = 30 * 1000;
@ -121,7 +121,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
@IConfigurationService private readonly configurationService: IConfigurationService,
@IProgressService private readonly progressService: IProgressService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IExtensionUrlTrustService private readonly extensionUrlTrustService: IExtensionUrlTrustService
@IProductService private readonly productService: IProductService
) {
this.userTrustedExtensionsStorage = new UserTrustedExtensionIdStorage(storageService);
@ -166,7 +166,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
}
const trusted = options?.trusted
|| (options?.originalUrl ? await this.extensionUrlTrustService.isExtensionUrlTrusted(extensionId, options.originalUrl) : false)
|| this.productService.trustedExtensionProtocolHandlers?.includes(extensionId)
|| this.didUserTrustExtension(ExtensionIdentifier.toKey(extensionId));
if (!trusted) {

View file

@ -55,7 +55,6 @@ import 'vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayout';
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/encryption/electron-sandbox/encryptionService';
import 'vs/workbench/services/secrets/electron-sandbox/secretStorageService';
import 'vs/workbench/services/localization/electron-sandbox/languagePackService';

View file

@ -41,7 +41,6 @@ import 'vs/workbench/services/keybinding/browser/keyboardLayoutService';
import 'vs/workbench/services/extensions/browser/extensionService';
import 'vs/workbench/services/extensionManagement/browser/webExtensionsScannerService';
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/url/browser/urlService';
import 'vs/workbench/services/update/browser/updateService';