Skip to content

Commit d35066b

Browse files
authored
Revert "disable, restart extension host, uninstall and remove problematic extension (microsoft#242249)" (microsoft#242310)
This reverts commit 4e6f06d.
1 parent d9bf09f commit d35066b

File tree

12 files changed

+95
-144
lines changed

12 files changed

+95
-144
lines changed

src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -723,22 +723,14 @@ export abstract class AbstractExtensionManagementService extends CommontExtensio
723723
this.logService.info('Successfully uninstalled extension from the profile', `${extension.identifier.id}@${extension.manifest.version}`, uninstallOptions.profileLocation.toString());
724724
}
725725
reportTelemetry(this.telemetryService, 'extensionGallery:uninstall', { extensionData: getLocalExtensionTelemetryData(extension), error });
726-
this._onDidUninstallExtension.fire({ identifier: extension.identifier, context: uninstallOptions.context, error: error?.code, profileLocation: uninstallOptions.profileLocation, applicationScoped: extension.isApplicationScoped });
726+
this._onDidUninstallExtension.fire({ identifier: extension.identifier, error: error?.code, profileLocation: uninstallOptions.profileLocation, applicationScoped: extension.isApplicationScoped });
727727
};
728728

729729
const allTasks: IUninstallExtensionTask[] = [];
730730
const processedTasks: IUninstallExtensionTask[] = [];
731731
const alreadyRequestedUninstalls: Promise<any>[] = [];
732-
const extensionsToRemove: ILocalExtension[] = [];
733732

734733
const installedExtensionsMap = new ResourceMap<ILocalExtension[]>();
735-
const getInstalledExtensions = async (profileLocation: URI) => {
736-
let installed = installedExtensionsMap.get(profileLocation);
737-
if (!installed) {
738-
installedExtensionsMap.set(profileLocation, installed = await this.getInstalled(ExtensionType.User, profileLocation));
739-
}
740-
return installed;
741-
};
742734

743735
for (const { extension, options } of extensions) {
744736
const uninstallOptions: UninstallExtensionTaskOptions = {
@@ -752,32 +744,14 @@ export abstract class AbstractExtensionManagementService extends CommontExtensio
752744
} else {
753745
allTasks.push(createUninstallExtensionTask(extension, uninstallOptions));
754746
}
755-
756-
if (uninstallOptions.remove) {
757-
extensionsToRemove.push(extension);
758-
for (const profile of this.userDataProfilesService.profiles) {
759-
if (this.uriIdentityService.extUri.isEqual(profile.extensionsResource, uninstallOptions.profileLocation)) {
760-
continue;
761-
}
762-
const installed = await getInstalledExtensions(profile.extensionsResource);
763-
const profileExtension = installed.find(e => areSameExtensions(e.identifier, extension.identifier));
764-
if (profileExtension) {
765-
const uninstallOptionsWithProfile = { ...uninstallOptions, profileLocation: profile.extensionsResource };
766-
const uninstallExtensionTask = this.uninstallingExtensions.get(getUninstallExtensionTaskKey(profileExtension, uninstallOptionsWithProfile));
767-
if (uninstallExtensionTask) {
768-
this.logService.info('Extensions is already requested to uninstall', profileExtension.identifier.id);
769-
alreadyRequestedUninstalls.push(uninstallExtensionTask.waitUntilTaskIsFinished());
770-
} else {
771-
allTasks.push(createUninstallExtensionTask(profileExtension, uninstallOptionsWithProfile));
772-
}
773-
}
774-
}
775-
}
776747
}
777748

778749
try {
779750
for (const task of allTasks.slice(0)) {
780-
const installed = await getInstalledExtensions(task.options.profileLocation);
751+
let installed = installedExtensionsMap.get(task.options.profileLocation);
752+
if (!installed) {
753+
installedExtensionsMap.set(task.options.profileLocation, installed = await this.getInstalled(ExtensionType.User, task.options.profileLocation));
754+
}
781755

782756
if (task.options.donotIncludePack) {
783757
this.logService.info('Uninstalling the extension without including packed extension', `${task.extension.identifier.id}@${task.extension.manifest.version}`);
@@ -825,10 +799,6 @@ export abstract class AbstractExtensionManagementService extends CommontExtensio
825799
for (const task of allTasks) {
826800
postUninstallExtension(task.extension, task.options);
827801
}
828-
829-
if (extensionsToRemove.length) {
830-
await this.joinAllSettled(extensionsToRemove.map(extension => this.removeExtension(extension)));
831-
}
832802
} catch (e) {
833803
const error = toExtensionManagementError(e);
834804
for (const task of allTasks) {
@@ -925,7 +895,6 @@ export abstract class AbstractExtensionManagementService extends CommontExtensio
925895
protected abstract createInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: InstallExtensionTaskOptions): IInstallExtensionTask;
926896
protected abstract createUninstallExtensionTask(extension: ILocalExtension, options: UninstallExtensionTaskOptions): IUninstallExtensionTask;
927897
protected abstract copyExtension(extension: ILocalExtension, fromProfileLocation: URI, toProfileLocation: URI, metadata?: Partial<Metadata>): Promise<ILocalExtension>;
928-
protected abstract removeExtension(extension: ILocalExtension): Promise<void>;
929898
}
930899

931900
export function toExtensionManagementError(error: Error, code?: ExtensionManagementErrorCode): ExtensionManagementError {

src/vs/platform/extensionManagement/common/extensionManagement.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ export const EXTENSION_INSTALL_SKIP_PUBLISHER_TRUST_CONTEXT = 'skipPublisherTrus
2323
export const EXTENSION_INSTALL_SOURCE_CONTEXT = 'extensionInstallSource';
2424
export const EXTENSION_INSTALL_DEP_PACK_CONTEXT = 'dependecyOrPackExtensionInstall';
2525
export const EXTENSION_INSTALL_CLIENT_TARGET_PLATFORM_CONTEXT = 'clientTargetPlatform';
26-
export const EXTENSION_UNINSTALL_MALICIOUS_CONTEXT = 'uninstallMaliciousExtension';
2726

2827
export const enum ExtensionInstallSource {
2928
COMMAND = 'command',
@@ -416,7 +415,6 @@ export interface UninstallExtensionEvent {
416415

417416
export interface DidUninstallExtensionEvent {
418417
readonly identifier: IExtensionIdentifier;
419-
readonly context?: IStringDictionary<any>;
420418
readonly error?: string;
421419
readonly profileLocation: URI;
422420
readonly applicationScoped?: boolean;
@@ -551,10 +549,6 @@ export type UninstallOptions = {
551549
readonly donotCheckDependents?: boolean;
552550
readonly versionOnly?: boolean;
553551
readonly remove?: boolean;
554-
/**
555-
* Context passed through to DidUninstallExtensionEvent
556-
*/
557-
context?: IStringDictionary<any>;
558552
};
559553

560554
export interface IExtensionManagementParticipant {

src/vs/platform/extensionManagement/node/extensionManagementService.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,10 +214,6 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi
214214
return local;
215215
}
216216

217-
protected removeExtension(extension: ILocalExtension): Promise<void> {
218-
return this.extensionsScanner.deleteExtension(extension, 'remove');
219-
}
220-
221217
protected copyExtension(extension: ILocalExtension, fromProfileLocation: URI, toProfileLocation: URI, metadata: Partial<Metadata>): Promise<ILocalExtension> {
222218
return this.extensionsScanner.copyExtension(extension, fromProfileLocation, toProfileLocation, metadata);
223219
}

src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer,
1717
import { InstallSpecificVersionOfExtensionAction, ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, SetColorThemeAction, SetFileIconThemeAction, SetProductIconThemeAction, ClearLanguageAction, ToggleAutoUpdateForExtensionAction, ToggleAutoUpdatesForPublisherAction, TogglePreReleaseExtensionAction, InstallAnotherVersionAction, InstallAction } from './extensionsActions.js';
1818
import { ExtensionsInput } from '../common/extensionsInput.js';
1919
import { ExtensionEditor } from './extensionEditor.js';
20-
import { StatusUpdater, ExtensionsViewletViewsContribution, ExtensionsViewPaneContainer, BuiltInExtensionsContext, SearchMarketplaceExtensionsContext, RecommendedExtensionsContext, DefaultViewsContext, ExtensionsSortByContext, SearchHasTextContext, ExtensionsSearchValueContext } from './extensionsViewlet.js';
20+
import { StatusUpdater, MaliciousExtensionChecker, ExtensionsViewletViewsContribution, ExtensionsViewPaneContainer, BuiltInExtensionsContext, SearchMarketplaceExtensionsContext, RecommendedExtensionsContext, DefaultViewsContext, ExtensionsSortByContext, SearchHasTextContext, ExtensionsSearchValueContext } from './extensionsViewlet.js';
2121
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from '../../../../platform/configuration/common/configurationRegistry.js';
2222
import * as jsonContributionRegistry from '../../../../platform/jsonschemas/common/jsonContributionRegistry.js';
2323
import { ExtensionsConfigurationSchema, ExtensionsConfigurationSchemaId } from '../common/extensionsFileTemplate.js';
@@ -1670,7 +1670,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
16701670
title: localize('download VSIX', "Download VSIX"),
16711671
menu: {
16721672
id: MenuId.ExtensionContext,
1673-
when: ContextKeyExpr.and(ContextKeyExpr.equals('extensionStatus', 'uninstalled'), ContextKeyExpr.not('extensionDisallowInstall'), ContextKeyExpr.has('isGalleryExtension')),
1673+
when: ContextKeyExpr.and(ContextKeyExpr.equals('extensionStatus', 'uninstalled'), ContextKeyExpr.has('isGalleryExtension')),
16741674
order: this.productService.quality === 'stable' ? 0 : 1
16751675
},
16761676
run: async (accessor: ServicesAccessor, extensionId: string) => {
@@ -1683,7 +1683,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
16831683
title: localize('download pre-release', "Download Pre-Release VSIX"),
16841684
menu: {
16851685
id: MenuId.ExtensionContext,
1686-
when: ContextKeyExpr.and(ContextKeyExpr.equals('extensionStatus', 'uninstalled'), ContextKeyExpr.not('extensionDisallowInstall'), ContextKeyExpr.has('isGalleryExtension'), ContextKeyExpr.has('extensionHasPreReleaseVersion')),
1686+
when: ContextKeyExpr.and(ContextKeyExpr.equals('extensionStatus', 'uninstalled'), ContextKeyExpr.has('isGalleryExtension'), ContextKeyExpr.has('extensionHasPreReleaseVersion')),
16871687
order: this.productService.quality === 'stable' ? 1 : 0
16881688
},
16891689
run: async (accessor: ServicesAccessor, extensionId: string) => {
@@ -1997,6 +1997,7 @@ class TrustedPublishersInitializer implements IWorkbenchContribution {
19971997
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
19981998
workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Restored);
19991999
workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Eventually);
2000+
workbenchRegistry.registerWorkbenchContribution(MaliciousExtensionChecker, LifecyclePhase.Eventually);
20002001
workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase.Restored);
20012002
workbenchRegistry.registerWorkbenchContribution(ExtensionsViewletViewsContribution, LifecyclePhase.Restored);
20022003
workbenchRegistry.registerWorkbenchContribution(ExtensionActivationProgress, LifecyclePhase.Eventually);

src/vs/workbench/contrib/extensions/browser/extensionsActions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1250,7 +1250,7 @@ async function getContextMenuActionsGroups(extension: IExtension | undefined | n
12501250
cksOverlay.push(['galleryExtensionHasPreReleaseVersion', extension.gallery?.hasPreReleaseVersion]);
12511251
cksOverlay.push(['extensionHasPreReleaseVersion', extension.hasPreReleaseVersion]);
12521252
cksOverlay.push(['extensionHasReleaseVersion', extension.hasReleaseVersion]);
1253-
cksOverlay.push(['extensionDisallowInstall', extension.isMalicious || extension.deprecationInfo?.disallowInstall]);
1253+
cksOverlay.push(['extensionDisallowInstall', !!extension.deprecationInfo?.disallowInstall]);
12541254
cksOverlay.push(['isExtensionAllowed', allowedExtensionsService.isAllowed({ id: extension.identifier.id, publisherDisplayName: extension.publisherDisplayName }) === true]);
12551255
cksOverlay.push(['isPreReleaseExtensionAllowed', allowedExtensionsService.isAllowed({ id: extension.identifier.id, publisherDisplayName: extension.publisherDisplayName, prerelease: true }) === true]);
12561256
cksOverlay.push(['extensionIsUnsigned', extension.gallery && !extension.gallery.isSigned]);

src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import './media/extensionsViewlet.css';
77
import { localize, localize2 } from '../../../../nls.js';
8-
import { Delayer } from '../../../../base/common/async.js';
8+
import { timeout, Delayer, Promises } from '../../../../base/common/async.js';
99
import { isCancellationError } from '../../../../base/common/errors.js';
1010
import { createErrorWithActions } from '../../../../base/common/errorMessage.js';
1111
import { IWorkbenchContribution } from '../../../common/contributions.js';
@@ -18,6 +18,7 @@ import { IInstantiationService, ServicesAccessor } from '../../../../platform/in
1818
import { IExtensionService } from '../../../services/extensions/common/extensions.js';
1919
import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, CloseExtensionDetailsOnViewChangeKey, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, WORKSPACE_RECOMMENDATIONS_VIEW_ID, AutoCheckUpdatesConfigurationKey, OUTDATED_EXTENSIONS_VIEW_ID, CONTEXT_HAS_GALLERY, extensionsSearchActionsMenu, AutoRestartConfigurationKey } from '../common/extensions.js';
2020
import { InstallLocalExtensionsInRemoteAction, InstallRemoteExtensionsInLocalAction } from './extensionsActions.js';
21+
import { IExtensionManagementService } from '../../../../platform/extensionManagement/common/extensionManagement.js';
2122
import { IWorkbenchExtensionEnablementService, IExtensionManagementServerService, IExtensionManagementServer } from '../../../services/extensionManagement/common/extensionManagement.js';
2223
import { ExtensionsInput } from '../common/extensionsInput.js';
2324
import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, ServerInstalledExtensionsView, DefaultRecommendedExtensionsView, UntrustedWorkspaceUnsupportedExtensionsView, UntrustedWorkspacePartiallySupportedExtensionsView, VirtualWorkspaceUnsupportedExtensionsView, VirtualWorkspacePartiallySupportedExtensionsView, DefaultPopularExtensionsView, DeprecatedExtensionsView, SearchMarketplaceExtensionsView, RecentlyUpdatedExtensionsView, OutdatedExtensionsView, StaticQueryExtensionsView, NONE_CATEGORY } from './extensionsViews.js';
@@ -33,20 +34,22 @@ import { IWorkspaceContextService } from '../../../../platform/workspace/common/
3334
import { IContextKeyService, ContextKeyExpr, RawContextKey, IContextKey } from '../../../../platform/contextkey/common/contextkey.js';
3435
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
3536
import { ILogService } from '../../../../platform/log/common/log.js';
36-
import { INotificationService } from '../../../../platform/notification/common/notification.js';
37+
import { INotificationService, NotificationPriority } from '../../../../platform/notification/common/notification.js';
38+
import { IHostService } from '../../../services/host/browser/host.js';
3739
import { IWorkbenchLayoutService } from '../../../services/layout/browser/layoutService.js';
3840
import { ViewPaneContainer } from '../../../browser/parts/views/viewPaneContainer.js';
3941
import { ViewPane } from '../../../browser/parts/views/viewPane.js';
4042
import { Query } from '../common/extensionQuery.js';
4143
import { SuggestEnabledInput } from '../../codeEditor/browser/suggestEnabledInput/suggestEnabledInput.js';
4244
import { alert } from '../../../../base/browser/ui/aria/aria.js';
43-
import { EXTENSION_CATEGORIES } from '../../../../platform/extensions/common/extensions.js';
45+
import { EXTENSION_CATEGORIES, ExtensionType } from '../../../../platform/extensions/common/extensions.js';
4446
import { Registry } from '../../../../platform/registry/common/platform.js';
4547
import { ILabelService } from '../../../../platform/label/common/label.js';
4648
import { MementoObject } from '../../../common/memento.js';
4749
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
4850
import { IPreferencesService } from '../../../services/preferences/common/preferences.js';
4951
import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND } from '../../../common/theme.js';
52+
import { IWorkbenchEnvironmentService } from '../../../services/environment/common/environmentService.js';
5053
import { VirtualWorkspaceContext, WorkbenchStateContext } from '../../../common/contextkeys.js';
5154
import { ICommandService } from '../../../../platform/commands/common/commands.js';
5255
import { installLocalInRemoteIcon } from './extensionsIcons.js';
@@ -56,6 +59,7 @@ import { IPaneCompositePartService } from '../../../services/panecomposite/brows
5659
import { coalesce } from '../../../../base/common/arrays.js';
5760
import { extractEditorsAndFilesDropData } from '../../../../platform/dnd/browser/dnd.js';
5861
import { extname } from '../../../../base/common/resources.js';
62+
import { isMalicious } from '../../../../platform/extensionManagement/common/extensionManagementUtil.js';
5963
import { ILocalizedString } from '../../../../platform/action/common/action.js';
6064
import { registerNavigableContainer } from '../../../browser/actions/widgetNavigationCommands.js';
6165
import { MenuWorkbenchToolBar } from '../../../../platform/actions/browser/toolbar.js';
@@ -963,3 +967,52 @@ export class StatusUpdater extends Disposable implements IWorkbenchContribution
963967
}
964968
}
965969
}
970+
971+
export class MaliciousExtensionChecker implements IWorkbenchContribution {
972+
973+
constructor(
974+
@IExtensionManagementService private readonly extensionsManagementService: IExtensionManagementService,
975+
@IHostService private readonly hostService: IHostService,
976+
@ILogService private readonly logService: ILogService,
977+
@INotificationService private readonly notificationService: INotificationService,
978+
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
979+
) {
980+
if (!this.environmentService.disableExtensions) {
981+
this.loopCheckForMaliciousExtensions();
982+
}
983+
}
984+
985+
private loopCheckForMaliciousExtensions(): void {
986+
this.checkForMaliciousExtensions()
987+
.then(() => timeout(1000 * 60 * 5)) // every five minutes
988+
.then(() => this.loopCheckForMaliciousExtensions());
989+
}
990+
991+
private checkForMaliciousExtensions(): Promise<void> {
992+
return this.extensionsManagementService.getExtensionsControlManifest().then(extensionsControlManifest => {
993+
994+
return this.extensionsManagementService.getInstalled(ExtensionType.User).then(installed => {
995+
const maliciousExtensions = installed.filter(e => isMalicious(e.identifier, extensionsControlManifest));
996+
997+
if (maliciousExtensions.length) {
998+
return Promises.settled(maliciousExtensions.map(e => this.extensionsManagementService.uninstall(e).then(() => {
999+
this.notificationService.prompt(
1000+
Severity.Warning,
1001+
localize('malicious warning', "We have uninstalled '{0}' which was reported to be problematic.", e.identifier.id),
1002+
[{
1003+
label: localize('reloadNow', "Reload Now"),
1004+
run: () => this.hostService.reload()
1005+
}],
1006+
{
1007+
sticky: true,
1008+
priority: NotificationPriority.URGENT
1009+
}
1010+
);
1011+
})));
1012+
} else {
1013+
return Promise.resolve(undefined);
1014+
}
1015+
}).then(() => undefined);
1016+
}, err => this.logService.error(err));
1017+
}
1018+
}

0 commit comments

Comments
 (0)