abstractExtensionManagementService.ts ×32

Frontier kind: Code frontier

unlabeled · c_38d9dfd5d7ed

7 tests · 19031 LOC · 89 files · introduces 0 tests · 395 LOC · 4 files

Introduces — evidence that enters the hierarchy at this concept

Code
53 ranges395 lines · 4 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
2636 ranges19031 lines · 89 files · Browse complete extent
All tests (intent)
7 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

4 files ranked by introduced lines: 395 introduced LOC across 53 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts 190 introduced LOC · 32 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- abstractExtensionManagementService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { distinct, isNonEmptyArray } from '../../../base/common/arrays.js';
7 > import { Barrier, CancelablePromise, createCancelablePromise } from '../../../base/common/async.js';
8 > import { CancellationToken } from '../../../base/common/cancellation.js';
9 > import { CancellationError, getErrorMessage, isCancellationError } from '../../../base/common/errors.js';
10 > import { Emitter, Event } from '../../../base/common/event.js';
11 > import { Disposable, toDisposable } from '../../../base/common/lifecycle.js';
12 > import { ResourceMap } from '../../../base/common/map.js';
13 > import { isWeb } from '../../../base/common/platform.js';
14 > import { URI } from '../../../base/common/uri.js';
15 > import * as nls from '../../../nls.js';
16 > import {
17 > ExtensionManagementError, IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementParticipant, IGalleryExtension, ILocalExtension, InstallOperation,
18 > IExtensionsControlManifest, StatisticType, isTargetPlatformCompatible, TargetPlatformToString, ExtensionManagementErrorCode,
19 > InstallOptions, UninstallOptions, Metadata, InstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionResult, UninstallExtensionEvent, IExtensionManagementService, InstallExtensionInfo, EXTENSION_INSTALL_DEP_PACK_CONTEXT, ExtensionGalleryError,
20 > IProductVersion, ExtensionGalleryErrorCode,
21 > EXTENSION_INSTALL_SOURCE_CONTEXT,
22 > DidUpdateExtensionMetadata,
23 > UninstallExtensionInfo,
24 > ExtensionSignatureVerificationCode,
25 > IAllowedExtensionsService
26 > } from './extensionManagement.js';
27 > import { areSameExtensions, ExtensionKey, getGalleryExtensionId, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, isMalicious } from './extensionManagementUtil.js';
28 > import { ExtensionType, IExtensionManifest, isApplicationScopedExtension, TargetPlatform } from '../../extensions/common/extensions.js';
29 > import { ILogService } from '../../log/common/log.js';
30 > import { IProductService } from '../../product/common/productService.js';
31 > import { ITelemetryService } from '../../telemetry/common/telemetry.js';
32 > import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js';
33 > import { IUserDataProfilesService } from '../../userDataProfile/common/userDataProfile.js';
34 > import { IMarkdownString, MarkdownString } from '../../../base/common/htmlContent.js';
35 >
36 > export type InstallableExtension = { readonly manifest: IExtensionManifest; extension: IGalleryExtension | URI; options: InstallOptions };
37 >
38 > export type InstallExtensionTaskOptions = InstallOptions & { readonly profileLocation: URI; readonly productVersion: IProductVersion };
39 > export interface IInstallExtensionTask {
40 > readonly manifest: IExtensionManifest;
41 > readonly identifier: IExtensionIdentifier;
42 > readonly source: IGalleryExtension | URI;
43 > readonly operation: InstallOperation;
44 > readonly options: InstallExtensionTaskOptions;
45 > readonly verificationStatus?: ExtensionSignatureVerificationCode;
46 > run(): Promise<ILocalExtension>;
47 > waitUntilTaskIsFinished(): Promise<ILocalExtension>;
48 > cancel(): void;
49 > }
50 >
51 > export type UninstallExtensionTaskOptions = UninstallOptions & { readonly profileLocation: URI };
52 > export interface IUninstallExtensionTask {
53 > readonly options: UninstallExtensionTaskOptions;
54 > readonly extension: ILocalExtension;
55 > run(): Promise<void>;
56 > waitUntilTaskIsFinished(): Promise<void>;
57 > cancel(): void;
58 > }
59 >
60 > export abstract class CommontExtensionManagementService extends Disposable implements IExtensionManagementService {
61 >
62 > _serviceBrand: undefined;
63 >
64 > readonly preferPreReleases: boolean;
65 >
66 > constructor(
67 @IProductService protected readonly productService: IProductService,
68 @IAllowedExtensionsService protected readonly allowedExtensionsService: IAllowedExtensionsService,
71 this.preferPreReleases = this.productService.quality !== 'stable';
72 }
74 > async canInstall(extension: IGalleryExtension): Promise<true | IMarkdownString> {
75 const allowedToInstall = this.allowedExtensionsService.isAllowed({ id: extension.identifier.id, publisherDisplayName: extension.publisherDisplayName });
76 if (allowedToInstall !== true) {
86 return true;
87 }
89 > protected async isExtensionPlatformCompatible(extension: IGalleryExtension): Promise<boolean> {
90 const currentTargetPlatform = await this.getTargetPlatform();
91 return extension.allTargetPlatforms.some(targetPlatform => isTargetPlatformCompatible(targetPlatform, extension.allTargetPlatforms, currentTargetPlatform));
92 }
94 > abstract readonly onInstallExtension: Event<InstallExtensionEvent>;
95 > abstract readonly onDidInstallExtensions: Event<readonly InstallExtensionResult[]>;
96 > abstract readonly onUninstallExtension: Event<UninstallExtensionEvent>;
97 > abstract readonly onDidUninstallExtension: Event<DidUninstallExtensionEvent>;
98 > abstract readonly onDidUpdateExtensionMetadata: Event<DidUpdateExtensionMetadata>;
99 > abstract installFromGallery(extension: IGalleryExtension, options?: InstallOptions): Promise<ILocalExtension>;
100 > abstract installGalleryExtensions(extensions: InstallExtensionInfo[]): Promise<InstallExtensionResult[]>;
101 > abstract uninstall(extension: ILocalExtension, options?: UninstallOptions): Promise<void>;
102 > abstract uninstallExtensions(extensions: UninstallExtensionInfo[]): Promise<void>;
103 > abstract toggleApplicationScope(extension: ILocalExtension, fromProfileLocation: URI): Promise<ILocalExtension>;
104 > abstract getExtensionsControlManifest(): Promise<IExtensionsControlManifest>;
105 > abstract resetPinnedStateForAllUserExtensions(pinned: boolean): Promise<void>;
106 > abstract registerParticipant(pariticipant: IExtensionManagementParticipant): void;
107 > abstract getTargetPlatform(): Promise<TargetPlatform>;
108 > abstract zip(extension: ILocalExtension): Promise<URI>;
109 > abstract getManifest(vsix: URI): Promise<IExtensionManifest>;
110 > abstract install(vsix: URI, options?: InstallOptions): Promise<ILocalExtension>;
111 > abstract installFromLocation(location: URI, profileLocation: URI): Promise<ILocalExtension>;
112 > abstract installExtensionsFromProfile(extensions: IExtensionIdentifier[], fromProfileLocation: URI, toProfileLocation: URI): Promise<ILocalExtension[]>;
113 > abstract getInstalled(type?: ExtensionType, profileLocation?: URI, productVersion?: IProductVersion): Promise<ILocalExtension[]>;
114 > abstract copyExtensions(fromProfileLocation: URI, toProfileLocation: URI): Promise<void>;
115 > abstract download(extension: IGalleryExtension, operation: InstallOperation, donotVerifySignature: boolean): Promise<URI>;
116 > abstract cleanUp(): Promise<void>;
117 > abstract updateMetadata(local: ILocalExtension, metadata: Partial<Metadata>, profileLocation: URI): Promise<ILocalExtension>;
118 > }
119 >
120 > export abstract class AbstractExtensionManagementService extends CommontExtensionManagementService implements IExtensionManagementService {
121 >
122 > declare readonly _serviceBrand: undefined;
123 >
124 > private extensionsControlManifest: Promise<IExtensionsControlManifest> | undefined;
125 > private lastReportTimestamp = 0;
126 > private readonly installingExtensions = new Map<string, { task: IInstallExtensionTask; waitingTasks: IInstallExtensionTask[] }>();
127 > private readonly uninstallingExtensions = new Map<string, IUninstallExtensionTask>();
128 >
129 > private readonly _onInstallExtension = this._register(new Emitter<InstallExtensionEvent>());
130 > get onInstallExtension() { return this._onInstallExtension.event; }
131 >
132 > protected readonly _onDidInstallExtensions = this._register(new Emitter<InstallExtensionResult[]>());
133 > get onDidInstallExtensions() { return this._onDidInstallExtensions.event; }
134 >
135 > protected readonly _onUninstallExtension = this._register(new Emitter<UninstallExtensionEvent>());
136 > get onUninstallExtension() { return this._onUninstallExtension.event; }
137 >
138 > protected _onDidUninstallExtension = this._register(new Emitter<DidUninstallExtensionEvent>());
139 > get onDidUninstallExtension() { return this._onDidUninstallExtension.event; }
140 >
141 > protected readonly _onDidUpdateExtensionMetadata = this._register(new Emitter<DidUpdateExtensionMetadata>());
142 > get onDidUpdateExtensionMetadata() { return this._onDidUpdateExtensionMetadata.event; }
143 >
144 > private readonly participants: IExtensionManagementParticipant[] = [];
145 >
146 > constructor(
147 @IExtensionGalleryService protected readonly galleryService: IExtensionGalleryService,
148 @ITelemetryService protected readonly telemetryService: ITelemetryService,
161 }));
162 }
164 > async installFromGallery(extension: IGalleryExtension, options: InstallOptions = {}): Promise<ILocalExtension> {
165 try {
166 const results = await this.installGalleryExtensions([{ extension, options }]);
186 }
187 }
189 > async installGalleryExtensions(extensions: InstallExtensionInfo[]): Promise<InstallExtensionResult[]> {
190 if (!this.galleryService.isEnabled()) {
191 throw new ExtensionManagementError(nls.localize('MarketPlaceDisabled', "Marketplace is not enabled"), ExtensionManagementErrorCode.NotAllowed);
210 return results;
211 }
213 > async uninstall(extension: ILocalExtension, options?: UninstallOptions): Promise<void> {
214 this.logService.trace('ExtensionManagementService#uninstall', extension.identifier.id);
215 return this.uninstallExtensions([{ extension, options }]);
216 }
218 > async toggleApplicationScope(extension: ILocalExtension, fromProfileLocation: URI): Promise<ILocalExtension> {
219 if (isApplicationScopedExtension(extension.manifest) || extension.isBuiltin) {
220 return extension;
260 return this.extensionsControlManifest;
261 }
263 > registerParticipant(participant: IExtensionManagementParticipant): void {
264 this.participants.push(participant);
265 }
267 > async resetPinnedStateForAllUserExtensions(pinned: boolean): Promise<void> {
268 try {
269 await this.joinAllSettled(this.userDataProfilesService.profiles.map(
282 }
283 }
285 > protected async installExtensions(extensions: InstallableExtension[]): Promise<InstallExtensionResult[]> {
286 const installExtensionResultsMap = new Map<string, InstallExtensionResult & { profileLocation: URI }>();
287 const installingExtensionsMap = new Map<string, { task: IInstallExtensionTask; root: IInstallExtensionTask | undefined; uninstallTaskToWaitFor?: IUninstallExtensionTask }>();
563 return results;
564 }
566 > private async getOtherProfilesToUpdateExtension(tasks: IInstallExtensionTask[]): Promise<[URI, IInstallExtensionTask][]> {
567 const otherProfilesToUpdate: [URI, IInstallExtensionTask][] = [];
568 const profileExtensionsCache = new ResourceMap<ILocalExtension[]>();
593 return otherProfilesToUpdate;
594 }
596 > private canWaitForTask(taskToWait: IInstallExtensionTask, taskToWaitFor: IInstallExtensionTask): boolean {
597 for (const [, { task, waitingTasks }] of this.installingExtensions.entries()) {
598 if (task === taskToWait) {
614 return true;
615 }
617 > private async joinAllSettled<T>(promises: Promise<T>[], errorCode?: ExtensionManagementErrorCode): Promise<T[]> {
618 const results: T[] = [];
619 const errors: ExtensionManagementError[] = [];
645 throw error;
646 }
648 > private async getAllDepsAndPackExtensions(extensionIdentifier: IExtensionIdentifier, manifest: IExtensionManifest, preferPreRelease: boolean, productVersion: IProductVersion, installed: ILocalExtension[]): Promise<{ gallery: IGalleryExtension; manifest: IExtensionManifest }[]> {
649 if (!this.galleryService.isEnabled()) {
650 return [];
701 return allDependenciesAndPacks;
702 }
704 > private async checkAndGetCompatibleVersion(extension: IGalleryExtension, sameVersion: boolean, installPreRelease: boolean, productVersion: IProductVersion): Promise<{ extension: IGalleryExtension; manifest: IExtensionManifest }> {
705 let compatibleExtension: IGalleryExtension | null;
706
747 return { extension: compatibleExtension, manifest };
748 }
750 > protected async getCompatibleVersion(extension: IGalleryExtension, sameVersion: boolean, includePreRelease: boolean, productVersion: IProductVersion): Promise<IGalleryExtension | null> {
751 const targetPlatform = await this.getTargetPlatform();
752 let compatibleExtension: IGalleryExtension | null = null;
770 return compatibleExtension;
771 }
773 > private getUninstallExtensionTaskKey(identifier: IExtensionIdentifier, profileLocation: URI, version?: string): string {
774 return `${identifier.id.toLowerCase()}${version ? `-${version}` : ''}@${profileLocation.toString()}`;
775 }
777 > async uninstallExtensions(extensions: UninstallExtensionInfo[]): Promise<void> {
778
779 const getUninstallExtensionTaskKey = (extension: ILocalExtension, uninstallOptions: UninstallExtensionTaskOptions) => this.getUninstallExtensionTaskKey(extension.identifier, uninstallOptions.profileLocation, uninstallOptions.versionOnly ? extension.manifest.version : undefined);
939 }
940 }
942 > private checkForDependents(extensionsToUninstall: ILocalExtension[], installed: ILocalExtension[], extensionToUninstall: ILocalExtension): void {
943 for (const extension of extensionsToUninstall) {
944 const dependents = this.getDependents(extension, installed);
951 }
952 }
954 > private getDependentsErrorMessage(dependingExtension: ILocalExtension, dependents: ILocalExtension[], extensionToUninstall: ILocalExtension): string {
955 if (extensionToUninstall === dependingExtension) {
956 if (dependents.length === 1) {
980
981 }
983 > private getAllPackExtensionsToUninstall(extension: ILocalExtension, installed: ILocalExtension[], checked: ILocalExtension[] = []): ILocalExtension[] {
984 if (checked.indexOf(extension) !== -1) {
985 return [];
1000 return [];
1001 }
1003 > private getDependents(extension: ILocalExtension, installed: ILocalExtension[]): ILocalExtension[] {
1004 return installed.filter(e => e.manifest.extensionDependencies && e.manifest.extensionDependencies.some(id => areSameExtensions({ id }, extension.identifier)));
1005 }
1007 > private async updateControlCache(): Promise<IExtensionsControlManifest> {
1008 try {
1009 this.logService.trace('ExtensionManagementService.updateControlCache');
1014 }
1015 }
1017 > protected abstract getCurrentExtensionsManifestLocation(): URI;
1018 > protected abstract createInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: InstallExtensionTaskOptions): IInstallExtensionTask;
1019 > protected abstract createUninstallExtensionTask(extension: ILocalExtension, options: UninstallExtensionTaskOptions): IUninstallExtensionTask;
1020 > protected abstract copyExtension(extension: ILocalExtension, fromProfileLocation: URI, toProfileLocation: URI, metadata?: Partial<Metadata>): Promise<ILocalExtension>;
1021 > protected abstract moveExtension(extension: ILocalExtension, fromProfileLocation: URI, toProfileLocation: URI, metadata?: Partial<Metadata>): Promise<ILocalExtension>;
1022 > protected abstract removeExtension(extension: ILocalExtension, fromProfileLocation: URI): Promise<void>;
1023 > protected abstract deleteExtension(extension: ILocalExtension): Promise<void>;
1024 > }
1025 >
1026 > export function toExtensionManagementError(error: Error, code?: ExtensionManagementErrorCode): ExtensionManagementError {
1027 if (error instanceof ExtensionManagementError) {
1028 return error;
1104 });
1105 }
1107 > export abstract class AbstractExtensionTask<T> {
1108
1109 private readonly barrier = new Barrier();
1110 > private cancellablePromise: CancelablePromise<T> | undefined; abstractExtensionManagementService.ts
1111 >
1112 > async waitUntilTaskIsFinished(): Promise<T> {
1113 await this.barrier.wait();
1114 return this.cancellablePromise!;
1115 }
1117 > run(): Promise<T> {
1118 if (!this.cancellablePromise) {
1119 this.cancellablePromise = createCancelablePromise(token => this.doRun(token));
1122 return this.cancellablePromise;
1123 }
1125 > cancel(): void {
1126 if (!this.cancellablePromise) {
1127 this.cancellablePromise = createCancelablePromise(token => {
src/vs/platform/extensionManagement/node/extensionDownloader.ts 129 introduced LOC · 14 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensionDownloader.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Promises } from '../../../base/common/async.js';
7 > import { getErrorMessage } from '../../../base/common/errors.js';
8 > import { Disposable } from '../../../base/common/lifecycle.js';
9 > import { Schemas } from '../../../base/common/network.js';
10 > import { joinPath } from '../../../base/common/resources.js';
11 > import * as semver from '../../../base/common/semver/semver.js';
12 > import { URI } from '../../../base/common/uri.js';
13 > import { generateUuid } from '../../../base/common/uuid.js';
14 > import { Promises as FSPromises } from '../../../base/node/pfs.js';
15 > import { buffer, CorruptZipMessage } from '../../../base/node/zip.js';
16 > import { INativeEnvironmentService } from '../../environment/common/environment.js';
17 > import { toExtensionManagementError } from '../common/abstractExtensionManagementService.js';
18 > import { ExtensionManagementError, ExtensionManagementErrorCode, ExtensionSignatureVerificationCode, IExtensionGalleryService, IGalleryExtension, InstallOperation } from '../common/extensionManagement.js';
19 > import { ExtensionKey, groupByExtension } from '../common/extensionManagementUtil.js';
20 > import { fromExtractError } from './extensionManagementUtil.js';
21 > import { IExtensionSignatureVerificationService } from './extensionSignatureVerificationService.js';
22 > import { TargetPlatform } from '../../extensions/common/extensions.js';
23 > import { FileOperationResult, IFileService, IFileStatWithMetadata, toFileOperationResult } from '../../files/common/files.js';
24 > import { ILogService } from '../../log/common/log.js';
25 > import { ITelemetryService } from '../../telemetry/common/telemetry.js';
26 > import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js';
27 >
28 > type RetryDownloadClassification = {
29 > owner: 'sandy081';
30 > comment: 'Event reporting the retry of downloading';
31 > extensionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Extension Id' };
32 > attempts: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true; comment: 'Number of Attempts' };
33 > };
34 > type RetryDownloadEvent = {
35 > extensionId: string;
36 > attempts: number;
37 > };
38 >
39 > export class ExtensionsDownloader extends Disposable {
40 >
41 > private static readonly SignatureArchiveExtension = '.sigzip';
42 >
43 > readonly extensionsDownloadDir: URI;
44 > private readonly extensionsTrashDir: URI;
45 > private readonly cache: number;
46 > private readonly cleanUpPromise: Promise<void>;
47 >
48 > constructor(
49 > @INativeEnvironmentService environmentService: INativeEnvironmentService,
50 > @IFileService private readonly fileService: IFileService,
51 > @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
52 > @IExtensionSignatureVerificationService private readonly extensionSignatureVerificationService: IExtensionSignatureVerificationService,
53 > @ITelemetryService private readonly telemetryService: ITelemetryService,
54 > @IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
55 > @ILogService private readonly logService: ILogService,
56 > ) {
57 > super();
58 > this.extensionsDownloadDir = environmentService.extensionsDownloadLocation;
59 > this.extensionsTrashDir = uriIdentityService.extUri.joinPath(environmentService.extensionsDownloadLocation, `.trash`);
60 > this.cache = 20; // Cache 20 downloaded VSIX files
61 > this.cleanUpPromise = this.cleanUp();
62 > }
63 >
64 > async download(extension: IGalleryExtension, operation: InstallOperation, verifySignature: boolean, clientTargetPlatform?: TargetPlatform): Promise<{ readonly location: URI; readonly verificationStatus: ExtensionSignatureVerificationCode | undefined }> {
65 > await this.cleanUpPromise;
66 >
67 > const location = await this.downloadVSIX(extension, operation);
68 >
69 > if (!verifySignature) {
70 return { location, verificationStatus: undefined };
71 }
79 signatureArchiveLocation = await this.downloadSignatureArchive(extension);
80 const verificationStatus = (await this.extensionSignatureVerificationService.verify(extension.identifier.id, extension.version, location.fsPath, signatureArchiveLocation.fsPath, clientTargetPlatform))?.code;
81 > if (verificationStatus === ExtensionSignatureVerificationCode.PackageIsInvalidZip || verificationStatus === ExtensionSignatureVerificationCode.SignatureArchiveIsInvalidZip) { extensionDownloader.ts
82 try {
83 // Delete the downloaded vsix if VSIX or signature archive is invalid
107 }
108 }
110 >
111 > private async downloadVSIX(extension: IGalleryExtension, operation: InstallOperation): Promise<URI> {
112 > try {
113 > const location = joinPath(this.extensionsDownloadDir, this.getName(extension));
114 > const attempts = await this.doDownload(extension, 'vsix', async () => {
115 > await this.downloadFile(extension, location, location => this.extensionGalleryService.download(extension, location, operation));
116 > try {
117 > await this.validate(location.fsPath, 'extension/package.json');
118 > } catch (error) {
119 try {
120 await this.fileService.del(location);
124 throw error;
125 }
126 > }, 2); extensionDownloader.ts
127 >
128 > if (attempts > 1) {
129 this.telemetryService.publicLog2<RetryDownloadEvent, RetryDownloadClassification>('extensiongallery:downloadvsix:retry', {
130 extensionId: extension.identifier.id,
132 });
133 }
135 > return location;
136 > } catch (e) {
137 throw toExtensionManagementError(e, ExtensionManagementErrorCode.Download);
138 }
140 >
141 > private async downloadSignatureArchive(extension: IGalleryExtension): Promise<URI> {
142 try {
143 const location = joinPath(this.extensionsDownloadDir, `${this.getName(extension)}${ExtensionsDownloader.SignatureArchiveExtension}`);
168 }
169 }
171 > private async downloadFile(extension: IGalleryExtension, location: URI, downloadFn: (location: URI) => Promise<void>): Promise<void> {
172 > // Do not download if exists
173 > if (await this.fileService.exists(location)) {
174 return;
175 }
177 > // Download directly if locaiton is not file scheme
178 > if (location.scheme !== Schemas.file) {
179 > await downloadFn(location);
180 > return;
181 > }
182
183 // Download to temporary location first only if file does not exist
206 }
207 }
209 >
210 > private async doDownload(extension: IGalleryExtension, name: string, downloadFn: () => Promise<void>, retries: number): Promise<number> {
211 > let attempts = 1;
212 > while (true) {
213 > try {
214 > await downloadFn();
215 > return attempts;
216 > } catch (e) {
217 if (attempts++ > retries) {
218 throw e;
220 this.logService.warn(`Failed downloading ${name}. ${getErrorMessage(e)}. Retry again...`, extension.identifier.id);
221 }
223 > }
224 >
225 > protected async validate(zipPath: string, filePath: string): Promise<void> {
226 try {
227 await buffer(zipPath, filePath);
230 }
231 }
233 > async delete(location: URI): Promise<void> {
234 await this.cleanUpPromise;
235 const trashRelativePath = this.uriIdentityService.extUri.relativePath(this.extensionsDownloadDir, location);
240 }
241 }
243 > private async cleanUp(): Promise<void> {
244 > try {
245 > if (!(await this.fileService.exists(this.extensionsDownloadDir))) {
246 > this.logService.trace('Extension VSIX downloads cache dir does not exist');
247 > return;
248 > }
249
250 try {
289 }));
290 }
291 > } catch (e) { extensionDownloader.ts
292 this.logService.error(e);
293 }
295 >
296 > private getName(extension: IGalleryExtension): string {
297 > return ExtensionKey.create(extension).toString().toLowerCase();
298 > }
299 >
300 > }
src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts 63 introduced LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensionSignatureVerificationService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { getErrorMessage } from '../../../base/common/errors.js';
7 > import { isDefined } from '../../../base/common/types.js';
8 > import { TargetPlatform } from '../../extensions/common/extensions.js';
9 > import { createDecorator } from '../../instantiation/common/instantiation.js';
10 > import { ILogService, LogLevel } from '../../log/common/log.js';
11 > import { ITelemetryService } from '../../telemetry/common/telemetry.js';
12 > import { ExtensionSignatureVerificationCode } from '../common/extensionManagement.js';
13 >
14 > export const IExtensionSignatureVerificationService = createDecorator<IExtensionSignatureVerificationService>('IExtensionSignatureVerificationService');
15 >
16 > export interface IExtensionSignatureVerificationResult {
17 > readonly code: ExtensionSignatureVerificationCode;
18 > }
19 >
20 > /**
21 > * A service for verifying signed extensions.
22 > */
23 > export interface IExtensionSignatureVerificationService {
24 > readonly _serviceBrand: undefined;
25 >
26 > /**
27 > * Verifies an extension file (.vsix) against a signature archive file.
28 > * @param extensionId The extension identifier.
29 > * @param version The extension version.
30 > * @param vsixFilePath The extension file path.
31 > * @param signatureArchiveFilePath The signature archive file path.
32 > * @returns returns the verification result or undefined if the verification was not executed.
33 > */
34 > verify(extensionId: string, version: string, vsixFilePath: string, signatureArchiveFilePath: string, clientTargetPlatform?: TargetPlatform): Promise<IExtensionSignatureVerificationResult | undefined>;
35 > }
36 >
37 > declare namespace vsceSign {
38 > export function verify(vsixFilePath: string, signatureArchiveFilePath: string, verbose: boolean): Promise<ExtensionSignatureVerificationResult>;
39 > }
40 >
41 > /**
42 > * Extension signature verification result
43 > */
44 > export interface ExtensionSignatureVerificationResult {
45 > readonly code: ExtensionSignatureVerificationCode;
46 > readonly didExecute: boolean;
47 > readonly internalCode?: number;
48 > readonly output?: string;
49 > }
50 >
51 > export class ExtensionSignatureVerificationService implements IExtensionSignatureVerificationService {
52 > declare readonly _serviceBrand: undefined;
53 >
54 > private moduleLoadingPromise: Promise<typeof vsceSign> | undefined;
55 >
56 > constructor(
57 @ILogService private readonly logService: ILogService,
58 @ITelemetryService private readonly telemetryService: ITelemetryService,
59 ) { }
61 > private vsceSign(): Promise<typeof vsceSign> {
62 if (!this.moduleLoadingPromise) {
63 this.moduleLoadingPromise = this.resolveVsceSign();
66 return this.moduleLoadingPromise;
67 }
69 > private async resolveVsceSign(): Promise<typeof vsceSign> {
70 const mod = '@vscode/vsce-sign';
71 return import(mod);
72 }
74 > public async verify(extensionId: string, version: string, vsixFilePath: string, signatureArchiveFilePath: string, clientTargetPlatform?: TargetPlatform): Promise<IExtensionSignatureVerificationResult | undefined> {
75 let module: typeof vsceSign;
76
src/vs/platform/extensionManagement/node/extensionManagementUtil.ts 13 introduced LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensionManagementUtil.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { buffer, ExtractError } from '../../../base/node/zip.js';
7 > import { localize } from '../../../nls.js';
8 > import { toExtensionManagementError } from '../common/abstractExtensionManagementService.js';
9 > import { ExtensionManagementError, ExtensionManagementErrorCode } from '../common/extensionManagement.js';
10 > import { IExtensionManifest } from '../../extensions/common/extensions.js';
11 >
12 > export function fromExtractError(e: Error): ExtensionManagementError {
13 let errorCode = ExtensionManagementErrorCode.Extract;
14 if (e instanceof ExtractError) {
21 return toExtensionManagementError(e, errorCode);
22 }
24 export async function getManifest(vsixPath: string): Promise<IExtensionManifest> {
25 let data;