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