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