Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/extensionManagement/common/allowedExtensionsService.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 { Disposable } from '../../../base/common/lifecycle.js';
7
import { URI } from '../../../base/common/uri.js';
8
import * as nls from '../../../nls.js';
9
import { IGalleryExtension, AllowedExtensionsConfigKey, IAllowedExtensionsService, AllowedExtensionsConfigValueType } from './extensionManagement.js';
10
import { ExtensionType, IExtension, TargetPlatform } from '../../extensions/common/extensions.js';
11
import { IProductService } from '../../product/common/productService.js';
12
import { IMarkdownString, MarkdownString } from '../../../base/common/htmlContent.js';
13
import { IConfigurationService } from '../../configuration/common/configuration.js';
14
import { isBoolean, isObject, isUndefined } from '../../../base/common/types.js';
15
import { Emitter } from '../../../base/common/event.js';
16
17
function isGalleryExtension(extension: any): extension is IGalleryExtension {
18
return extension.type === 'gallery';
19
}
20
21
function isIExtension(extension: any): extension is IExtension {
22
return extension.type === ExtensionType.User || extension.type === ExtensionType.System;
23
}
24
25
26
const VersionRegex = /^(?<version>\d+\.\d+\.\d+(-.*)?)(@(?<platform>.+))?$/;
27
28
export class AllowedExtensionsService extends Disposable implements IAllowedExtensionsService {
29
30
_serviceBrand: undefined;
31
32
private readonly publisherOrgs: string[];
33
34
private _allowedExtensionsConfigValue: AllowedExtensionsConfigValueType | undefined;
35
get allowedExtensionsConfigValue(): AllowedExtensionsConfigValueType | undefined {
36
return this._allowedExtensionsConfigValue;
37
}
38
private _onDidChangeAllowedExtensions = this._register(new Emitter<void>());
39
readonly onDidChangeAllowedExtensionsConfigValue = this._onDidChangeAllowedExtensions.event;
40
41
constructor(
42
@IProductService productService: IProductService,
43
@IConfigurationService protected readonly configurationService: IConfigurationService
44
) {
45
super();
46
this.publisherOrgs = productService.extensionPublisherOrgs?.map(p => p.toLowerCase()) ?? [];
47
this._allowedExtensionsConfigValue = this.getAllowedExtensionsValue();
48
this._register(this.configurationService.onDidChangeConfiguration(e => {
49
if (e.affectsConfiguration(AllowedExtensionsConfigKey)) {
50
this._allowedExtensionsConfigValue = this.getAllowedExtensionsValue();
51
this._onDidChangeAllowedExtensions.fire();
52
}
53
}));
54
}
55
56
private getAllowedExtensionsValue(): AllowedExtensionsConfigValueType | undefined {
57
const value = this.configurationService.getValue<AllowedExtensionsConfigValueType | undefined>(AllowedExtensionsConfigKey);
58
if (!isObject(value) || Array.isArray(value)) {
59
return undefined;
60
}
61
const entries = Object.entries(value).map(([key, value]) => [key.toLowerCase(), value]);
62
if (entries.length === 1 && entries[0][0] === '*' && entries[0][1] === true) {
63
return undefined;
64
}
65
return Object.fromEntries(entries);
66
}
67
68
isAllowed(extension: IGalleryExtension | IExtension | { id: string; publisherDisplayName: string | undefined; version?: string; prerelease?: boolean; targetPlatform?: TargetPlatform }): true | IMarkdownString {
69
if (!this._allowedExtensionsConfigValue) {
70
return true;
71
}
72
73
let id: string, version: string, targetPlatform: TargetPlatform, prerelease: boolean, publisher: string, publisherDisplayName: string | undefined;
74
75
if (isGalleryExtension(extension)) {
76
id = extension.identifier.id.toLowerCase();
77
version = extension.version;
78
prerelease = extension.properties.isPreReleaseVersion;
79
publisher = extension.publisher.toLowerCase();
80
publisherDisplayName = extension.publisherDisplayName.toLowerCase();
81
targetPlatform = extension.properties.targetPlatform;
82
} else if (isIExtension(extension)) {
83
id = extension.identifier.id.toLowerCase();
84
version = extension.manifest.version;
85
prerelease = extension.preRelease;
86
publisher = extension.manifest.publisher.toLowerCase();
87
publisherDisplayName = extension.publisherDisplayName?.toLowerCase();
88
targetPlatform = extension.targetPlatform;
89
} else {
90
id = extension.id.toLowerCase();
91
version = extension.version ?? '*';
92
targetPlatform = extension.targetPlatform ?? TargetPlatform.UNIVERSAL;
93
prerelease = extension.prerelease ?? false;
94
publisher = extension.id.substring(0, extension.id.indexOf('.')).toLowerCase();
95
publisherDisplayName = extension.publisherDisplayName?.toLowerCase();
96
}
97
98
const settingsCommandLink = URI.parse(`command:workbench.action.openSettings?${encodeURIComponent(JSON.stringify({ query: `@id:${AllowedExtensionsConfigKey}` }))}`).toString();
99
const extensionValue = this._allowedExtensionsConfigValue[id];
100
const extensionReason = new MarkdownString(nls.localize('specific extension not allowed', "it is not in the [allowed list]({0})", settingsCommandLink));
101
if (!isUndefined(extensionValue)) {
102
if (isBoolean(extensionValue)) {
103
return extensionValue ? true : extensionReason;
104
}
105
if (extensionValue === 'stable' && prerelease) {
106
return new MarkdownString(nls.localize('extension prerelease not allowed', "the pre-release versions of this extension are not in the [allowed list]({0})", settingsCommandLink));
107
}
108
if (version !== '*' && Array.isArray(extensionValue) && !extensionValue.some(v => {
109
const match = VersionRegex.exec(v);
110
if (match && match.groups) {
111
const { platform: p, version: v } = match.groups;
112
if (v !== version) {
113
return false;
114
}
115
if (targetPlatform !== TargetPlatform.UNIVERSAL && p && targetPlatform !== p) {
116
return false;
117
}
118
return true;
119
}
120
return false;
121
})) {
122
return new MarkdownString(nls.localize('specific version of extension not allowed', "the version {0} of this extension is not in the [allowed list]({1})", version, settingsCommandLink));
123
}
124
return true;
125
}
126
127
const publisherKey = publisherDisplayName && this.publisherOrgs.includes(publisherDisplayName) ? publisherDisplayName : publisher;
128
const publisherValue = this._allowedExtensionsConfigValue[publisherKey];
129
if (!isUndefined(publisherValue)) {
130
if (isBoolean(publisherValue)) {
131
return publisherValue ? true : new MarkdownString(nls.localize('publisher not allowed', "the extensions from this publisher are not in the [allowed list]({1})", publisherKey, settingsCommandLink));
132
}
133
if (publisherValue === 'stable' && prerelease) {
134
return new MarkdownString(nls.localize('prerelease versions from this publisher not allowed', "the pre-release versions from this publisher are not in the [allowed list]({1})", publisherKey, settingsCommandLink));
135
}
136
return true;
137
}
138
139
if (this._allowedExtensionsConfigValue['*'] === true) {
140
return true;
141
}
142
143
return extensionReason;
144
}
145
}
146
147