Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/extensionManagement/common/extensionManagement.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
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 { CancellationToken } from '../../../base/common/cancellation.js';
7
import { IStringDictionary } from '../../../base/common/collections.js';
8
import { Event } from '../../../base/common/event.js';
9
import { IMarkdownString } from '../../../base/common/htmlContent.js';
10
import { IPager } from '../../../base/common/paging.js';
11
import { Platform } from '../../../base/common/platform.js';
12
import { URI } from '../../../base/common/uri.js';
13
import { localize, localize2 } from '../../../nls.js';
14
import { ConfigurationScope, Extensions, IConfigurationRegistry } from '../../configuration/common/configurationRegistry.js';
15
import { ExtensionType, IExtension, IExtensionManifest, TargetPlatform } from '../../extensions/common/extensions.js';
16
import { FileOperationError, FileOperationResult, IFileService, IFileStat } from '../../files/common/files.js';
17
import { createDecorator } from '../../instantiation/common/instantiation.js';
18
import { Registry } from '../../registry/common/platform.js';
19
import { IExtensionGalleryManifest } from './extensionGalleryManifest.js';
20
21
export const EXTENSION_IDENTIFIER_PATTERN = '^([a-z0-9A-Z][a-z0-9-A-Z]*)\\.([a-z0-9A-Z][a-z0-9-A-Z]*)$';
22
export const EXTENSION_IDENTIFIER_REGEX = new RegExp(EXTENSION_IDENTIFIER_PATTERN);
23
export const WEB_EXTENSION_TAG = '__web_extension';
24
export const EXTENSION_INSTALL_SKIP_WALKTHROUGH_CONTEXT = 'skipWalkthrough';
25
export const EXTENSION_INSTALL_SKIP_PUBLISHER_TRUST_CONTEXT = 'skipPublisherTrust';
26
export const EXTENSION_INSTALL_SOURCE_CONTEXT = 'extensionInstallSource';
27
export const EXTENSION_INSTALL_DEP_PACK_CONTEXT = 'dependecyOrPackExtensionInstall';
28
export const EXTENSION_INSTALL_CLIENT_TARGET_PLATFORM_CONTEXT = 'clientTargetPlatform';
29
30
export const enum ExtensionInstallSource {
31
COMMAND = 'command',
32
SETTINGS_SYNC = 'settingsSync',
33
}
34
35
export interface IProductVersion {
36
readonly version: string;
37
readonly date?: string;
38
}
39
40
export function TargetPlatformToString(targetPlatform: TargetPlatform) {
41
switch (targetPlatform) {
42
case TargetPlatform.WIN32_X64: return 'Windows 64 bit';
43
case TargetPlatform.WIN32_ARM64: return 'Windows ARM';
44
45
case TargetPlatform.LINUX_X64: return 'Linux 64 bit';
46
case TargetPlatform.LINUX_ARM64: return 'Linux ARM 64';
47
case TargetPlatform.LINUX_ARMHF: return 'Linux ARM';
48
49
case TargetPlatform.ALPINE_X64: return 'Alpine Linux 64 bit';
50
case TargetPlatform.ALPINE_ARM64: return 'Alpine ARM 64';
51
52
case TargetPlatform.DARWIN_X64: return 'Mac';
53
case TargetPlatform.DARWIN_ARM64: return 'Mac Silicon';
54
55
case TargetPlatform.WEB: return 'Web';
56
57
case TargetPlatform.UNIVERSAL: return TargetPlatform.UNIVERSAL;
58
case TargetPlatform.UNKNOWN: return TargetPlatform.UNKNOWN;
59
case TargetPlatform.UNDEFINED: return TargetPlatform.UNDEFINED;
60
}
61
}
62
63
export function toTargetPlatform(targetPlatform: string): TargetPlatform {
64
switch (targetPlatform) {
65
case TargetPlatform.WIN32_X64: return TargetPlatform.WIN32_X64;
66
case TargetPlatform.WIN32_ARM64: return TargetPlatform.WIN32_ARM64;
67
68
case TargetPlatform.LINUX_X64: return TargetPlatform.LINUX_X64;
69
case TargetPlatform.LINUX_ARM64: return TargetPlatform.LINUX_ARM64;
70
case TargetPlatform.LINUX_ARMHF: return TargetPlatform.LINUX_ARMHF;
71
72
case TargetPlatform.ALPINE_X64: return TargetPlatform.ALPINE_X64;
73
case TargetPlatform.ALPINE_ARM64: return TargetPlatform.ALPINE_ARM64;
74
75
case TargetPlatform.DARWIN_X64: return TargetPlatform.DARWIN_X64;
76
case TargetPlatform.DARWIN_ARM64: return TargetPlatform.DARWIN_ARM64;
77
78
case TargetPlatform.WEB: return TargetPlatform.WEB;
79
80
case TargetPlatform.UNIVERSAL: return TargetPlatform.UNIVERSAL;
81
default: return TargetPlatform.UNKNOWN;
82
}
83
}
84
85
export function getTargetPlatform(platform: Platform | 'alpine', arch: string | undefined): TargetPlatform {
86
switch (platform) {
87
case Platform.Windows:
88
if (arch === 'x64') {
89
return TargetPlatform.WIN32_X64;
90
}
91
if (arch === 'arm64') {
92
return TargetPlatform.WIN32_ARM64;
93
}
94
return TargetPlatform.UNKNOWN;
95
96
case Platform.Linux:
97
if (arch === 'x64') {
98
return TargetPlatform.LINUX_X64;
99
}
100
if (arch === 'arm64') {
101
return TargetPlatform.LINUX_ARM64;
102
}
103
if (arch === 'arm') {
104
return TargetPlatform.LINUX_ARMHF;
105
}
106
return TargetPlatform.UNKNOWN;
107
108
case 'alpine':
109
if (arch === 'x64') {
110
return TargetPlatform.ALPINE_X64;
111
}
112
if (arch === 'arm64') {
113
return TargetPlatform.ALPINE_ARM64;
114
}
115
return TargetPlatform.UNKNOWN;
116
117
case Platform.Mac:
118
if (arch === 'x64') {
119
return TargetPlatform.DARWIN_X64;
120
}
121
if (arch === 'arm64') {
122
return TargetPlatform.DARWIN_ARM64;
123
}
124
return TargetPlatform.UNKNOWN;
125
126
case Platform.Web: return TargetPlatform.WEB;
127
}
128
}
129
130
export function isNotWebExtensionInWebTargetPlatform(allTargetPlatforms: TargetPlatform[], productTargetPlatform: TargetPlatform): boolean {
131
// Not a web extension in web target platform
132
return productTargetPlatform === TargetPlatform.WEB && !allTargetPlatforms.includes(TargetPlatform.WEB);
133
}
134
135
export function isTargetPlatformCompatible(extensionTargetPlatform: TargetPlatform, allTargetPlatforms: TargetPlatform[], productTargetPlatform: TargetPlatform): boolean {
136
// Not compatible when extension is not a web extension in web target platform
137
if (isNotWebExtensionInWebTargetPlatform(allTargetPlatforms, productTargetPlatform)) {
138
return false;
139
}
140
141
// Compatible when extension target platform is not defined
142
if (extensionTargetPlatform === TargetPlatform.UNDEFINED) {
143
return true;
144
}
145
146
// Compatible when extension target platform is universal
147
if (extensionTargetPlatform === TargetPlatform.UNIVERSAL) {
148
return true;
149
}
150
151
// Not compatible when extension target platform is unknown
152
if (extensionTargetPlatform === TargetPlatform.UNKNOWN) {
153
return false;
154
}
155
156
// Compatible when extension and product target platforms matches
157
if (extensionTargetPlatform === productTargetPlatform) {
158
return true;
159
}
160
161
return false;
162
}
163
164
export interface IGalleryExtensionProperties {
165
dependencies?: string[];
166
extensionPack?: string[];
167
engine?: string;
168
enabledApiProposals?: string[];
169
localizedLanguages?: string[];
170
targetPlatform: TargetPlatform;
171
isPreReleaseVersion: boolean;
172
executesCode?: boolean;
173
}
174
175
export interface IGalleryExtensionAsset {
176
uri: string;
177
fallbackUri: string;
178
}
179
180
export interface IGalleryExtensionAssets {
181
manifest: IGalleryExtensionAsset | null;
182
readme: IGalleryExtensionAsset | null;
183
changelog: IGalleryExtensionAsset | null;
184
license: IGalleryExtensionAsset | null;
185
repository: IGalleryExtensionAsset | null;
186
download: IGalleryExtensionAsset;
187
icon: IGalleryExtensionAsset | null;
188
signature: IGalleryExtensionAsset | null;
189
coreTranslations: [string, IGalleryExtensionAsset][];
190
}
191
192
export function isIExtensionIdentifier(thing: any): thing is IExtensionIdentifier {
193
return thing
194
&& typeof thing === 'object'
195
&& typeof thing.id === 'string'
196
&& (!thing.uuid || typeof thing.uuid === 'string');
197
}
198
199
export interface IExtensionIdentifier {
200
id: string;
201
uuid?: string;
202
}
203
204
export interface IGalleryExtensionIdentifier extends IExtensionIdentifier {
205
uuid: string;
206
}
207
208
export interface IGalleryExtensionVersion {
209
version: string;
210
date: string;
211
isPreReleaseVersion: boolean;
212
targetPlatforms: TargetPlatform[];
213
}
214
215
export interface IGalleryExtension {
216
type: 'gallery';
217
name: string;
218
identifier: IGalleryExtensionIdentifier;
219
version: string;
220
displayName: string;
221
publisherId: string;
222
publisher: string;
223
publisherDisplayName: string;
224
publisherDomain?: { link: string; verified: boolean };
225
publisherLink?: string;
226
publisherSponsorLink?: string;
227
description: string;
228
installCount: number;
229
rating: number;
230
ratingCount: number;
231
categories: readonly string[];
232
tags: readonly string[];
233
releaseDate: number;
234
lastUpdated: number;
235
preview: boolean;
236
private: boolean;
237
hasPreReleaseVersion: boolean;
238
hasReleaseVersion: boolean;
239
isSigned: boolean;
240
allTargetPlatforms: TargetPlatform[];
241
assets: IGalleryExtensionAssets;
242
properties: IGalleryExtensionProperties;
243
detailsLink?: string;
244
ratingLink?: string;
245
supportLink?: string;
246
telemetryData?: any;
247
queryContext?: IStringDictionary<any>;
248
}
249
250
export type InstallSource = 'gallery' | 'vsix' | 'resource';
251
252
export interface IGalleryMetadata {
253
id: string;
254
publisherId: string;
255
private: boolean;
256
publisherDisplayName: string;
257
isPreReleaseVersion: boolean;
258
targetPlatform?: TargetPlatform;
259
}
260
261
export type Metadata = Partial<IGalleryMetadata & {
262
isApplicationScoped: boolean;
263
isMachineScoped: boolean;
264
isBuiltin: boolean;
265
isSystem: boolean;
266
updated: boolean;
267
preRelease: boolean;
268
hasPreReleaseVersion: boolean;
269
installedTimestamp: number;
270
pinned: boolean;
271
source: InstallSource;
272
size: number;
273
}>;
274
275
export interface ILocalExtension extends IExtension {
276
isWorkspaceScoped: boolean;
277
isMachineScoped: boolean;
278
isApplicationScoped: boolean;
279
publisherId: string | null;
280
installedTimestamp?: number;
281
isPreReleaseVersion: boolean;
282
hasPreReleaseVersion: boolean;
283
private: boolean;
284
preRelease: boolean;
285
updated: boolean;
286
pinned: boolean;
287
source: InstallSource;
288
size: number;
289
}
290
291
export const enum SortBy {
292
NoneOrRelevance = 'NoneOrRelevance',
293
LastUpdatedDate = 'LastUpdatedDate',
294
Title = 'Title',
295
PublisherName = 'PublisherName',
296
InstallCount = 'InstallCount',
297
PublishedDate = 'PublishedDate',
298
AverageRating = 'AverageRating',
299
WeightedRating = 'WeightedRating'
300
}
301
302
export const enum SortOrder {
303
Default = 0,
304
Ascending = 1,
305
Descending = 2
306
}
307
308
export const enum FilterType {
309
Category = 'Category',
310
ExtensionId = 'ExtensionId',
311
ExtensionName = 'ExtensionName',
312
ExcludeWithFlags = 'ExcludeWithFlags',
313
Featured = 'Featured',
314
SearchText = 'SearchText',
315
Tag = 'Tag',
316
Target = 'Target',
317
}
318
319
export interface IQueryOptions {
320
text?: string;
321
exclude?: string[];
322
pageSize?: number;
323
sortBy?: SortBy;
324
sortOrder?: SortOrder;
325
source?: string;
326
includePreRelease?: boolean;
327
productVersion?: IProductVersion;
328
}
329
330
export const enum StatisticType {
331
Install = 'install',
332
Uninstall = 'uninstall'
333
}
334
335
export interface IDeprecationInfo {
336
readonly disallowInstall?: boolean;
337
readonly extension?: {
338
readonly id: string;
339
readonly displayName: string;
340
readonly autoMigrate?: { readonly storage: boolean };
341
readonly preRelease?: boolean;
342
};
343
readonly settings?: readonly string[];
344
readonly additionalInfo?: string;
345
}
346
347
export interface ISearchPrefferedResults {
348
readonly query?: string;
349
readonly preferredResults?: string[];
350
}
351
352
export type MaliciousExtensionInfo = {
353
readonly extensionOrPublisher: IExtensionIdentifier | string;
354
readonly learnMoreLink?: string;
355
};
356
357
export interface IExtensionsControlManifest {
358
readonly malicious: ReadonlyArray<MaliciousExtensionInfo>;
359
readonly deprecated: IStringDictionary<IDeprecationInfo>;
360
readonly search: ISearchPrefferedResults[];
361
readonly autoUpdate?: IStringDictionary<string>;
362
}
363
364
export const enum InstallOperation {
365
None = 1,
366
Install,
367
Update,
368
Migrate,
369
}
370
371
export interface ITranslation {
372
contents: { [key: string]: {} };
373
}
374
375
export interface IExtensionInfo extends IExtensionIdentifier {
376
version?: string;
377
preRelease?: boolean;
378
hasPreRelease?: boolean;
379
}
380
381
export interface IExtensionQueryOptions {
382
targetPlatform?: TargetPlatform;
383
productVersion?: IProductVersion;
384
compatible?: boolean;
385
queryAllVersions?: boolean;
386
source?: string;
387
}
388
389
export interface IExtensionGalleryCapabilities {
390
readonly query: {
391
readonly sortBy: readonly SortBy[];
392
readonly filters: readonly FilterType[];
393
};
394
readonly allRepositorySigned: boolean;
395
}
396
397
export const IExtensionGalleryService = createDecorator<IExtensionGalleryService>('extensionGalleryService');
398
399
/**
400
* Service to interact with the Visual Studio Code Marketplace to get extensions.
401
* @throws Error if the Marketplace is not enabled or not reachable.
402
*/
403
export interface IExtensionGalleryService {
404
readonly _serviceBrand: undefined;
405
isEnabled(): boolean;
406
query(options: IQueryOptions, token: CancellationToken): Promise<IPager<IGalleryExtension>>;
407
getExtensions(extensionInfos: ReadonlyArray<IExtensionInfo>, token: CancellationToken): Promise<IGalleryExtension[]>;
408
getExtensions(extensionInfos: ReadonlyArray<IExtensionInfo>, options: IExtensionQueryOptions, token: CancellationToken): Promise<IGalleryExtension[]>;
409
isExtensionCompatible(extension: IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform, productVersion?: IProductVersion): Promise<boolean>;
410
getCompatibleExtension(extension: IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform, productVersion?: IProductVersion): Promise<IGalleryExtension | null>;
411
getAllCompatibleVersions(extensionIdentifier: IExtensionIdentifier, includePreRelease: boolean, targetPlatform: TargetPlatform): Promise<IGalleryExtensionVersion[]>;
412
getAllVersions(extensionIdentifier: IExtensionIdentifier): Promise<IGalleryExtensionVersion[]>;
413
download(extension: IGalleryExtension, location: URI, operation: InstallOperation): Promise<void>;
414
downloadSignatureArchive(extension: IGalleryExtension, location: URI): Promise<void>;
415
reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise<void>;
416
getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string>;
417
getManifest(extension: IGalleryExtension, token: CancellationToken): Promise<IExtensionManifest | null>;
418
getChangelog(extension: IGalleryExtension, token: CancellationToken): Promise<string>;
419
getCoreTranslation(extension: IGalleryExtension, languageId: string): Promise<ITranslation | null>;
420
getExtensionsControlManifest(): Promise<IExtensionsControlManifest>;
421
}
422
423
export interface InstallExtensionEvent {
424
readonly identifier: IExtensionIdentifier;
425
readonly source: URI | IGalleryExtension;
426
readonly profileLocation: URI;
427
readonly applicationScoped?: boolean;
428
readonly workspaceScoped?: boolean;
429
}
430
431
export interface InstallExtensionResult {
432
readonly identifier: IExtensionIdentifier;
433
readonly operation: InstallOperation;
434
readonly source?: URI | IGalleryExtension;
435
readonly local?: ILocalExtension;
436
readonly error?: Error;
437
readonly context?: IStringDictionary<any>;
438
readonly profileLocation: URI;
439
readonly applicationScoped?: boolean;
440
readonly workspaceScoped?: boolean;
441
}
442
443
export interface UninstallExtensionEvent {
444
readonly identifier: IExtensionIdentifier;
445
readonly profileLocation: URI;
446
readonly applicationScoped?: boolean;
447
readonly workspaceScoped?: boolean;
448
}
449
450
export interface DidUninstallExtensionEvent {
451
readonly identifier: IExtensionIdentifier;
452
readonly error?: string;
453
readonly profileLocation: URI;
454
readonly applicationScoped?: boolean;
455
readonly workspaceScoped?: boolean;
456
}
457
458
export interface DidUpdateExtensionMetadata {
459
readonly profileLocation: URI;
460
readonly local: ILocalExtension;
461
}
462
463
export const enum ExtensionGalleryErrorCode {
464
Timeout = 'Timeout',
465
Cancelled = 'Cancelled',
466
ClientError = 'ClientError',
467
ServerError = 'ServerError',
468
Failed = 'Failed',
469
DownloadFailedWriting = 'DownloadFailedWriting',
470
Offline = 'Offline',
471
}
472
473
export class ExtensionGalleryError extends Error {
474
constructor(message: string, readonly code: ExtensionGalleryErrorCode) {
475
super(message);
476
this.name = code;
477
}
478
}
479
480
export const enum ExtensionManagementErrorCode {
481
NotFound = 'NotFound',
482
Unsupported = 'Unsupported',
483
Deprecated = 'Deprecated',
484
Malicious = 'Malicious',
485
Incompatible = 'Incompatible',
486
IncompatibleApi = 'IncompatibleApi',
487
IncompatibleTargetPlatform = 'IncompatibleTargetPlatform',
488
ReleaseVersionNotFound = 'ReleaseVersionNotFound',
489
Invalid = 'Invalid',
490
Download = 'Download',
491
DownloadSignature = 'DownloadSignature',
492
DownloadFailedWriting = ExtensionGalleryErrorCode.DownloadFailedWriting,
493
UpdateMetadata = 'UpdateMetadata',
494
Extract = 'Extract',
495
Scanning = 'Scanning',
496
ScanningExtension = 'ScanningExtension',
497
ReadRemoved = 'ReadRemoved',
498
UnsetRemoved = 'UnsetRemoved',
499
Delete = 'Delete',
500
Rename = 'Rename',
501
IntializeDefaultProfile = 'IntializeDefaultProfile',
502
AddToProfile = 'AddToProfile',
503
InstalledExtensionNotFound = 'InstalledExtensionNotFound',
504
PostInstall = 'PostInstall',
505
CorruptZip = 'CorruptZip',
506
IncompleteZip = 'IncompleteZip',
507
PackageNotSigned = 'PackageNotSigned',
508
SignatureVerificationInternal = 'SignatureVerificationInternal',
509
SignatureVerificationFailed = 'SignatureVerificationFailed',
510
NotAllowed = 'NotAllowed',
511
Gallery = 'Gallery',
512
Cancelled = 'Cancelled',
513
Unknown = 'Unknown',
514
Internal = 'Internal',
515
}
516
517
export enum ExtensionSignatureVerificationCode {
518
'NotSigned' = 'NotSigned',
519
'Success' = 'Success',
520
'RequiredArgumentMissing' = 'RequiredArgumentMissing', // A required argument is missing.
521
'InvalidArgument' = 'InvalidArgument', // An argument is invalid.
522
'PackageIsUnreadable' = 'PackageIsUnreadable', // The extension package is unreadable.
523
'UnhandledException' = 'UnhandledException', // An unhandled exception occurred.
524
'SignatureManifestIsMissing' = 'SignatureManifestIsMissing', // The extension is missing a signature manifest file (.signature.manifest).
525
'SignatureManifestIsUnreadable' = 'SignatureManifestIsUnreadable', // The signature manifest is unreadable.
526
'SignatureIsMissing' = 'SignatureIsMissing', // The extension is missing a signature file (.signature.p7s).
527
'SignatureIsUnreadable' = 'SignatureIsUnreadable', // The signature is unreadable.
528
'CertificateIsUnreadable' = 'CertificateIsUnreadable', // The certificate is unreadable.
529
'SignatureArchiveIsUnreadable' = 'SignatureArchiveIsUnreadable',
530
'FileAlreadyExists' = 'FileAlreadyExists', // The output file already exists.
531
'SignatureArchiveIsInvalidZip' = 'SignatureArchiveIsInvalidZip',
532
'SignatureArchiveHasSameSignatureFile' = 'SignatureArchiveHasSameSignatureFile', // The signature archive has the same signature file.
533
'PackageIntegrityCheckFailed' = 'PackageIntegrityCheckFailed', // The package integrity check failed.
534
'SignatureIsInvalid' = 'SignatureIsInvalid', // The extension has an invalid signature file (.signature.p7s).
535
'SignatureManifestIsInvalid' = 'SignatureManifestIsInvalid', // The extension has an invalid signature manifest file (.signature.manifest).
536
'SignatureIntegrityCheckFailed' = 'SignatureIntegrityCheckFailed', // The extension's signature integrity check failed. Extension integrity is suspect.
537
'EntryIsMissing' = 'EntryIsMissing', // An entry referenced in the signature manifest was not found in the extension.
538
'EntryIsTampered' = 'EntryIsTampered', // The integrity check for an entry referenced in the signature manifest failed.
539
'Untrusted' = 'Untrusted', // An X.509 certificate in the extension signature is untrusted.
540
'CertificateRevoked' = 'CertificateRevoked', // An X.509 certificate in the extension signature has been revoked.
541
'SignatureIsNotValid' = 'SignatureIsNotValid', // The extension signature is invalid.
542
'UnknownError' = 'UnknownError', // An unknown error occurred.
543
'PackageIsInvalidZip' = 'PackageIsInvalidZip', // The extension package is not valid ZIP format.
544
'SignatureArchiveHasTooManyEntries' = 'SignatureArchiveHasTooManyEntries', // The signature archive has too many entries.
545
}
546
547
export class ExtensionManagementError extends Error {
548
constructor(message: string, readonly code: ExtensionManagementErrorCode) {
549
super(message);
550
this.name = code;
551
}
552
}
553
554
export interface InstallExtensionSummary {
555
failed: {
556
id: string;
557
installOptions: InstallOptions;
558
}[];
559
}
560
561
export type InstallOptions = {
562
isBuiltin?: boolean;
563
isWorkspaceScoped?: boolean;
564
isMachineScoped?: boolean;
565
isApplicationScoped?: boolean;
566
pinned?: boolean;
567
donotIncludePackAndDependencies?: boolean;
568
installGivenVersion?: boolean;
569
preRelease?: boolean;
570
installPreReleaseVersion?: boolean;
571
donotVerifySignature?: boolean;
572
operation?: InstallOperation;
573
profileLocation?: URI;
574
productVersion?: IProductVersion;
575
keepExisting?: boolean;
576
downloadExtensionsLocally?: boolean;
577
/**
578
* Context passed through to InstallExtensionResult
579
*/
580
context?: IStringDictionary<any>;
581
};
582
583
export type UninstallOptions = {
584
readonly profileLocation?: URI;
585
readonly donotIncludePack?: boolean;
586
readonly donotCheckDependents?: boolean;
587
readonly versionOnly?: boolean;
588
readonly remove?: boolean;
589
};
590
591
export interface IExtensionManagementParticipant {
592
postInstall(local: ILocalExtension, source: URI | IGalleryExtension, options: InstallOptions, token: CancellationToken): Promise<void>;
593
postUninstall(local: ILocalExtension, options: UninstallOptions, token: CancellationToken): Promise<void>;
594
}
595
596
export type InstallExtensionInfo = { readonly extension: IGalleryExtension; readonly options: InstallOptions };
597
export type UninstallExtensionInfo = { readonly extension: ILocalExtension; readonly options?: UninstallOptions };
598
599
export const IExtensionManagementService = createDecorator<IExtensionManagementService>('extensionManagementService');
600
export interface IExtensionManagementService {
601
readonly _serviceBrand: undefined;
602
603
readonly preferPreReleases: boolean;
604
605
onInstallExtension: Event<InstallExtensionEvent>;
606
onDidInstallExtensions: Event<readonly InstallExtensionResult[]>;
607
onUninstallExtension: Event<UninstallExtensionEvent>;
608
onDidUninstallExtension: Event<DidUninstallExtensionEvent>;
609
onDidUpdateExtensionMetadata: Event<DidUpdateExtensionMetadata>;
610
611
zip(extension: ILocalExtension): Promise<URI>;
612
getManifest(vsix: URI): Promise<IExtensionManifest>;
613
install(vsix: URI, options?: InstallOptions): Promise<ILocalExtension>;
614
canInstall(extension: IGalleryExtension): Promise<true | IMarkdownString>;
615
installFromGallery(extension: IGalleryExtension, options?: InstallOptions): Promise<ILocalExtension>;
616
installGalleryExtensions(extensions: InstallExtensionInfo[]): Promise<InstallExtensionResult[]>;
617
installFromLocation(location: URI, profileLocation: URI): Promise<ILocalExtension>;
618
installExtensionsFromProfile(extensions: IExtensionIdentifier[], fromProfileLocation: URI, toProfileLocation: URI): Promise<ILocalExtension[]>;
619
uninstall(extension: ILocalExtension, options?: UninstallOptions): Promise<void>;
620
uninstallExtensions(extensions: UninstallExtensionInfo[]): Promise<void>;
621
toggleApplicationScope(extension: ILocalExtension, fromProfileLocation: URI): Promise<ILocalExtension>;
622
getInstalled(type?: ExtensionType, profileLocation?: URI, productVersion?: IProductVersion, language?: string): Promise<ILocalExtension[]>;
623
getExtensionsControlManifest(): Promise<IExtensionsControlManifest>;
624
copyExtensions(fromProfileLocation: URI, toProfileLocation: URI): Promise<void>;
625
updateMetadata(local: ILocalExtension, metadata: Partial<Metadata>, profileLocation: URI): Promise<ILocalExtension>;
626
resetPinnedStateForAllUserExtensions(pinned: boolean): Promise<void>;
627
628
download(extension: IGalleryExtension, operation: InstallOperation, donotVerifySignature: boolean): Promise<URI>;
629
630
registerParticipant(pariticipant: IExtensionManagementParticipant): void;
631
getTargetPlatform(): Promise<TargetPlatform>;
632
633
cleanUp(): Promise<void>;
634
}
635
636
export const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/disabled';
637
export const ENABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/enabled';
638
export const IGlobalExtensionEnablementService = createDecorator<IGlobalExtensionEnablementService>('IGlobalExtensionEnablementService');
639
640
export interface IGlobalExtensionEnablementService {
641
readonly _serviceBrand: undefined;
642
readonly onDidChangeEnablement: Event<{ readonly extensions: IExtensionIdentifier[]; readonly source?: string }>;
643
644
getDisabledExtensions(): IExtensionIdentifier[];
645
enableExtension(extension: IExtensionIdentifier, source?: string): Promise<boolean>;
646
disableExtension(extension: IExtensionIdentifier, source?: string): Promise<boolean>;
647
648
}
649
650
export type IConfigBasedExtensionTip = {
651
readonly extensionId: string;
652
readonly extensionName: string;
653
readonly isExtensionPack: boolean;
654
readonly configName: string;
655
readonly important: boolean;
656
readonly whenNotInstalled?: string[];
657
};
658
659
export type IExecutableBasedExtensionTip = {
660
readonly extensionId: string;
661
readonly extensionName: string;
662
readonly isExtensionPack: boolean;
663
readonly exeName: string;
664
readonly exeFriendlyName: string;
665
readonly windowsPath?: string;
666
readonly whenNotInstalled?: string[];
667
};
668
669
export const IExtensionTipsService = createDecorator<IExtensionTipsService>('IExtensionTipsService');
670
export interface IExtensionTipsService {
671
readonly _serviceBrand: undefined;
672
673
getConfigBasedTips(folder: URI): Promise<IConfigBasedExtensionTip[]>;
674
getImportantExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]>;
675
getOtherExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]>;
676
}
677
678
export type AllowedExtensionsConfigValueType = IStringDictionary<boolean | string | string[]>;
679
680
export const IAllowedExtensionsService = createDecorator<IAllowedExtensionsService>('IAllowedExtensionsService');
681
export interface IAllowedExtensionsService {
682
readonly _serviceBrand: undefined;
683
684
readonly allowedExtensionsConfigValue: AllowedExtensionsConfigValueType | undefined;
685
readonly onDidChangeAllowedExtensionsConfigValue: Event<void>;
686
687
isAllowed(extension: IGalleryExtension | IExtension): true | IMarkdownString;
688
isAllowed(extension: { id: string; publisherDisplayName: string | undefined; version?: string; prerelease?: boolean; targetPlatform?: TargetPlatform }): true | IMarkdownString;
689
}
690
691
export async function computeSize(location: URI, fileService: IFileService): Promise<number> {
692
let stat: IFileStat;
693
try {
694
stat = await fileService.resolve(location);
695
} catch (e) {
696
if ((<FileOperationError>e).fileOperationResult === FileOperationResult.FILE_NOT_FOUND) {
697
return 0;
698
}
699
throw e;
700
}
701
if (stat.children) {
702
const sizes = await Promise.all(stat.children.map(c => computeSize(c.resource, fileService)));
703
return sizes.reduce((r, s) => r + s, 0);
704
}
705
return stat.size ?? 0;
706
}
707
708
export const ExtensionsLocalizedLabel = localize2('extensions', "Extensions");
709
export const PreferencesLocalizedLabel = localize2('preferences', 'Preferences');
710
export const AllowedExtensionsConfigKey = 'extensions.allowed';
711
export const VerifyExtensionSignatureConfigKey = 'extensions.verifySignature';
712
713
Registry.as<IConfigurationRegistry>(Extensions.Configuration)
714
.registerConfiguration({
715
id: 'extensions',
716
order: 30,
717
title: localize('extensionsConfigurationTitle', "Extensions"),
718
type: 'object',
719
properties: {
720
[AllowedExtensionsConfigKey]: {
721
// Note: Type is set only to object because to support policies generation during build time, where single type is expected.
722
type: 'object',
723
markdownDescription: localize('extensions.allowed', "Specify a list of extensions that are allowed to use. This helps maintain a secure and consistent development environment by restricting the use of unauthorized extensions. For more information on how to configure this setting, please visit the [Configure Allowed Extensions](https://code.visualstudio.com/docs/setup/enterprise#_configure-allowed-extensions) section."),
724
default: '*',
725
defaultSnippets: [{
726
body: {},
727
description: localize('extensions.allowed.none', "No extensions are allowed."),
728
}, {
729
body: {
730
'*': true
731
},
732
description: localize('extensions.allowed.all', "All extensions are allowed."),
733
}],
734
scope: ConfigurationScope.APPLICATION,
735
policy: {
736
name: 'AllowedExtensions',
737
minimumVersion: '1.96',
738
description: localize('extensions.allowed.policy', "Specify a list of extensions that are allowed to use. This helps maintain a secure and consistent development environment by restricting the use of unauthorized extensions. More information: https://code.visualstudio.com/docs/setup/enterprise#_configure-allowed-extensions"),
739
},
740
additionalProperties: false,
741
patternProperties: {
742
'([a-z0-9A-Z][a-z0-9-A-Z]*)\\.([a-z0-9A-Z][a-z0-9-A-Z]*)$': {
743
anyOf: [
744
{
745
type: ['boolean', 'string'],
746
enum: [true, false, 'stable'],
747
description: localize('extensions.allow.description', "Allow or disallow the extension."),
748
enumDescriptions: [
749
localize('extensions.allowed.enable.desc', "Extension is allowed."),
750
localize('extensions.allowed.disable.desc', "Extension is not allowed."),
751
localize('extensions.allowed.disable.stable.desc', "Allow only stable versions of the extension."),
752
],
753
},
754
{
755
type: 'array',
756
items: {
757
type: 'string',
758
},
759
description: localize('extensions.allow.version.description', "Allow or disallow specific versions of the extension. To specifcy a platform specific version, use the format `[email protected]`, e.g. `[email protected]`. Supported platforms are `win32-x64`, `win32-arm64`, `linux-x64`, `linux-arm64`, `linux-armhf`, `alpine-x64`, `alpine-arm64`, `darwin-x64`, `darwin-arm64`"),
760
},
761
]
762
},
763
'([a-z0-9A-Z][a-z0-9-A-Z]*)$': {
764
type: ['boolean', 'string'],
765
enum: [true, false, 'stable'],
766
description: localize('extension.publisher.allow.description', "Allow or disallow all extensions from the publisher."),
767
enumDescriptions: [
768
localize('extensions.publisher.allowed.enable.desc', "All extensions from the publisher are allowed."),
769
localize('extensions.publisher.allowed.disable.desc', "All extensions from the publisher are not allowed."),
770
localize('extensions.publisher.allowed.disable.stable.desc', "Allow only stable versions of the extensions from the publisher."),
771
],
772
},
773
'\\*': {
774
type: 'boolean',
775
enum: [true, false],
776
description: localize('extensions.allow.all.description', "Allow or disallow all extensions."),
777
enumDescriptions: [
778
localize('extensions.allow.all.enable', "Allow all extensions."),
779
localize('extensions.allow.all.disable', "Disallow all extensions.")
780
],
781
}
782
}
783
}
784
}
785
});
786
787
export function shouldRequireRepositorySignatureFor(isPrivate: boolean, galleryManifest: IExtensionGalleryManifest | null): boolean {
788
if (isPrivate) {
789
return galleryManifest?.capabilities.signing?.allPrivateRepositorySigned === true;
790
}
791
return galleryManifest?.capabilities.signing?.allPublicRepositorySigned === true;
792
}
793
794
795