Extension management - refactoring workspace trust signal (#116118)

This commit is contained in:
Ladislau Szomoru 2021-02-08 19:50:01 +01:00 committed by GitHub
parent c86be3bb57
commit e146dd28e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 50 deletions

View file

@ -41,7 +41,6 @@ import { FileAccess } from 'vs/base/common/network';
import { IIgnoredExtensionsManagementService } from 'vs/platform/userDataSync/common/ignoredExtensions';
import { IUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataSync';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IWorkspaceTrustService, WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust';
interface IExtensionStateProvider<T> {
(extension: Extension): T;
@ -525,8 +524,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
@IIgnoredExtensionsManagementService private readonly extensionsSyncManagementService: IIgnoredExtensionsManagementService,
@IUserDataAutoSyncService private readonly userDataAutoSyncService: IUserDataAutoSyncService,
@IProductService private readonly productService: IProductService,
@IContextKeyService contextKeyService: IContextKeyService,
@IWorkspaceTrustService private readonly workspaceTrustService: IWorkspaceTrustService
@IContextKeyService contextKeyService: IContextKeyService
) {
super();
this.hasOutdatedExtensionsContextKey = HasOutdatedExtensionsContext.bindTo(contextKeyService);
@ -1033,54 +1031,33 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
private async installFromVSIX(vsix: URI): Promise<IExtension> {
const manifest = await this.extensionManagementService.getManifest(vsix);
return this.promptForTrustIfNeededAndInstall(manifest, async () => {
const existingExtension = this.local.find(local => areSameExtensions(local.identifier, { id: getGalleryExtensionId(manifest.publisher, manifest.name) }));
const { identifier } = await this.extensionManagementService.install(vsix);
const existingExtension = this.local.find(local => areSameExtensions(local.identifier, { id: getGalleryExtensionId(manifest.publisher, manifest.name) }));
const { identifier } = await this.extensionManagementService.install(vsix);
if (existingExtension && existingExtension.latestVersion !== manifest.version) {
this.ignoreAutoUpdate(new ExtensionIdentifierWithVersion(identifier, manifest.version));
}
if (existingExtension && existingExtension.latestVersion !== manifest.version) {
this.ignoreAutoUpdate(new ExtensionIdentifierWithVersion(identifier, manifest.version));
}
return this.local.filter(local => areSameExtensions(local.identifier, identifier))[0];
});
return this.local.filter(local => areSameExtensions(local.identifier, identifier))[0];
}
private async installFromGallery(extension: IExtension, gallery: IGalleryExtension, installOptions?: InstallOptions): Promise<IExtension> {
const manifest = await extension.getManifest(CancellationToken.None);
if (manifest) {
this.promptForTrustIfNeededAndInstall(manifest, async () => {
this.installing.push(extension);
this._onChange.fire(extension);
try {
if (extension.state === ExtensionState.Installed && extension.local) {
await this.extensionManagementService.updateFromGallery(gallery, extension.local);
} else {
await this.extensionManagementService.installFromGallery(gallery, installOptions);
}
const ids: string[] | undefined = extension.identifier.uuid ? [extension.identifier.uuid] : undefined;
const names: string[] | undefined = extension.identifier.uuid ? undefined : [extension.identifier.id];
this.queryGallery({ names, ids, pageSize: 1 }, CancellationToken.None);
return this.local.filter(local => areSameExtensions(local.identifier, gallery.identifier))[0];
} finally {
this.installing = this.installing.filter(e => e !== extension);
this._onChange.fire(this.local.filter(e => areSameExtensions(e.identifier, extension.identifier))[0]);
}
});
this.installing.push(extension);
this._onChange.fire(extension);
try {
if (extension.state === ExtensionState.Installed && extension.local) {
await this.extensionManagementService.updateFromGallery(gallery, extension.local);
} else {
await this.extensionManagementService.installFromGallery(gallery, installOptions);
}
const ids: string[] | undefined = extension.identifier.uuid ? [extension.identifier.uuid] : undefined;
const names: string[] | undefined = extension.identifier.uuid ? undefined : [extension.identifier.id];
this.queryGallery({ names, ids, pageSize: 1 }, CancellationToken.None);
return this.local.filter(local => areSameExtensions(local.identifier, gallery.identifier))[0];
} finally {
this.installing = this.installing.filter(e => e !== extension);
this._onChange.fire(this.local.filter(e => areSameExtensions(e.identifier, extension.identifier))[0]);
}
return Promise.reject();
}
private async promptForTrustIfNeededAndInstall<T>(manifest: IExtensionManifest, installTask: () => Promise<T>): Promise<T> {
if (manifest.requiresWorkspaceTrust === 'onStart') {
const trustState = await this.workspaceTrustService.requireWorkspaceTrust(
{
immediate: true,
message: 'Installing this extension requires you to trust the contents of this workspace.'
});
return trustState === WorkspaceTrustState.Trusted ? installTask() : Promise.reject();
}
return installTask();
}
private promptAndSetEnablement(extensions: IExtension[], enablementState: EnablementState): Promise<any> {

View file

@ -25,6 +25,7 @@ import Severity from 'vs/base/common/severity';
import { canceled } from 'vs/base/common/errors';
import { IUserDataAutoSyncEnablementService, IUserDataSyncResourceEnablementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync';
import { Promises } from 'vs/base/common/async';
import { IWorkspaceTrustService, WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust';
export class ExtensionManagementService extends Disposable implements IWorkbenchExtensioManagementService {
@ -46,6 +47,7 @@ export class ExtensionManagementService extends Disposable implements IWorkbench
@IUserDataAutoSyncEnablementService private readonly userDataAutoSyncEnablementService: IUserDataAutoSyncEnablementService,
@IUserDataSyncResourceEnablementService private readonly userDataSyncResourceEnablementService: IUserDataSyncResourceEnablementService,
@IDialogService private readonly dialogService: IDialogService,
@IWorkspaceTrustService private readonly workspaceTrustService: IWorkspaceTrustService
) {
super();
if (this.extensionManagementServerService.localExtensionManagementServer) {
@ -128,9 +130,10 @@ export class ExtensionManagementService extends Disposable implements IWorkbench
}
reinstallFromGallery(extension: ILocalExtension): Promise<void> {
async reinstallFromGallery(extension: ILocalExtension): Promise<void> {
const server = this.getServer(extension);
if (server) {
await this.checkForWorkspaceTrust(extension.manifest);
return server.extensionManagementService.reinstallFromGallery(extension);
}
return Promise.reject(`Invalid location ${extension.location.toString()}`);
@ -191,8 +194,13 @@ export class ExtensionManagementService extends Disposable implements IWorkbench
return Promise.reject('No Servers to Install');
}
protected installVSIX(vsix: URI, server: IExtensionManagementServer): Promise<ILocalExtension> {
return server.extensionManagementService.install(vsix);
protected async installVSIX(vsix: URI, server: IExtensionManagementServer): Promise<ILocalExtension> {
const manifest = await this.getManifest(vsix);
if (manifest) {
await this.checkForWorkspaceTrust(manifest);
return server.extensionManagementService.install(vsix);
}
return Promise.reject('Unable to get the extension manifest.');
}
getManifest(vsix: URI): Promise<IExtensionManifest> {
@ -269,6 +277,7 @@ export class ExtensionManagementService extends Disposable implements IWorkbench
servers.push(this.extensionManagementServerService.localExtensionManagementServer);
}
}
await this.checkForWorkspaceTrust(manifest);
return Promises.settled(servers.map(server => server.extensionManagementService.installFromGallery(gallery, installOptions))).then(([local]) => local);
}
@ -346,4 +355,16 @@ export class ExtensionManagementService extends Disposable implements IWorkbench
private getServer(extension: ILocalExtension): IExtensionManagementServer | null {
return this.extensionManagementServerService.getExtensionManagementServer(extension);
}
protected async checkForWorkspaceTrust(manifest: IExtensionManifest): Promise<void> {
if (manifest.requiresWorkspaceTrust === 'onStart') {
const trustState = await this.workspaceTrustService.requireWorkspaceTrust(
{
immediate: true,
message: 'Installing this extension requires you to trust the contents of this workspace.'
});
return trustState === WorkspaceTrustState.Trusted ? Promise.resolve() : Promise.reject(canceled());
}
return Promise.resolve();
}
}

View file

@ -17,6 +17,7 @@ import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/enviro
import { joinPath } from 'vs/base/common/resources';
import { IUserDataAutoSyncEnablementService, IUserDataSyncResourceEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IWorkspaceTrustService } from 'vs/platform/workspace/common/workspaceTrust';
export class ExtensionManagementService extends BaseExtensionManagementService {
@ -30,8 +31,9 @@ export class ExtensionManagementService extends BaseExtensionManagementService {
@IUserDataAutoSyncEnablementService userDataAutoSyncEnablementService: IUserDataAutoSyncEnablementService,
@IUserDataSyncResourceEnablementService userDataSyncResourceEnablementService: IUserDataSyncResourceEnablementService,
@IDialogService dialogService: IDialogService,
@IWorkspaceTrustService workspaceTrustService: IWorkspaceTrustService
) {
super(extensionManagementServerService, extensionGalleryService, configurationService, productService, downloadService, userDataAutoSyncEnablementService, userDataSyncResourceEnablementService, dialogService);
super(extensionManagementServerService, extensionGalleryService, configurationService, productService, downloadService, userDataAutoSyncEnablementService, userDataSyncResourceEnablementService, dialogService, workspaceTrustService);
}
protected async installVSIX(vsix: URI, server: IExtensionManagementServer): Promise<ILocalExtension> {
@ -40,7 +42,13 @@ export class ExtensionManagementService extends BaseExtensionManagementService {
await this.downloadService.download(vsix, downloadedLocation);
vsix = downloadedLocation;
}
return server.extensionManagementService.install(vsix);
const manifest = await this.getManifest(vsix);
if (manifest) {
await this.checkForWorkspaceTrust(manifest);
return server.extensionManagementService.install(vsix);
}
return Promise.reject('Unable to get the extension manifest.');
}
}