mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 21:09:43 +00:00
Extension workspace trust request using product/settings files (#121021)
* Extension workspace trust request using product/settings files
This commit is contained in:
parent
601dec633b
commit
0c555419fe
|
@ -33,3 +33,28 @@ export function provideInstalledExtensionProposals(existing: string[], additiona
|
|||
return undefined;
|
||||
}
|
||||
|
||||
export function provideWorkspaceTrustExtensionProposals(existing: string[], range: vscode.Range): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList> {
|
||||
if (Array.isArray(existing)) {
|
||||
const extensions = vscode.extensions.all.filter(e => e.packageJSON.main);
|
||||
const extensionProposals = extensions.filter(e => existing.indexOf(e.id) === -1);
|
||||
if (extensionProposals.length) {
|
||||
return extensionProposals.map(e => {
|
||||
const item = new vscode.CompletionItem(e.id);
|
||||
const insertText = `"${e.id}": {\n\t"request": "onStart",\n\t"version": "${e.packageJSON.version}"\n}`;
|
||||
item.kind = vscode.CompletionItemKind.Value;
|
||||
item.insertText = insertText;
|
||||
item.range = range;
|
||||
item.filterText = insertText;
|
||||
return item;
|
||||
});
|
||||
} else {
|
||||
const example = new vscode.CompletionItem(localize('exampleExtension', "Example"));
|
||||
example.insertText = '"vscode.csharp: {\n\t"request": "onStart",\n\t"version": "0.0.0"\n}`;"';
|
||||
example.kind = vscode.CompletionItemKind.Value;
|
||||
example.range = range;
|
||||
return [example];
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import * as vscode from 'vscode';
|
||||
import { getLocation, Location, parse } from 'jsonc-parser';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { provideInstalledExtensionProposals } from './extensionsProposals';
|
||||
import { provideInstalledExtensionProposals, provideWorkspaceTrustExtensionProposals } from './extensionsProposals';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
@ -60,6 +60,15 @@ export class SettingsDocument {
|
|||
return provideInstalledExtensionProposals(alreadyConfigured, `: [\n\t"ui"\n]`, range, true);
|
||||
}
|
||||
|
||||
// security.workspace.trust.extensionRequest
|
||||
if (location.path[0] === 'security.workspace.trust.extensionRequest' && location.path.length === 2 && location.isAtPropertyKey) {
|
||||
let alreadyConfigured: string[] = [];
|
||||
try {
|
||||
alreadyConfigured = Object.keys(parse(this.document.getText())['security.workspace.trust.extensionRequest']);
|
||||
} catch (e) {/* ignore error */ }
|
||||
return provideWorkspaceTrustExtensionProposals(alreadyConfigured, range);
|
||||
}
|
||||
|
||||
return this.provideLanguageOverridesCompletionItems(location, position);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,11 @@ export type ConfigurationSyncStore = {
|
|||
authenticationProviders: IStringDictionary<{ scopes: string[] }>
|
||||
};
|
||||
|
||||
export type ExtensionWorkspaceTrustRequest = {
|
||||
readonly default?: 'never' | 'onStart' | 'onDemand',
|
||||
readonly override?: 'never' | 'onStart' | 'onDemand'
|
||||
};
|
||||
|
||||
export interface IProductConfiguration {
|
||||
readonly version: string;
|
||||
readonly date?: string;
|
||||
|
@ -116,6 +121,7 @@ export interface IProductConfiguration {
|
|||
readonly extensionKind?: { readonly [extensionId: string]: ('ui' | 'workspace' | 'web')[]; };
|
||||
readonly extensionSyncedKeys?: { readonly [extensionId: string]: string[]; };
|
||||
readonly extensionAllowedProposedApi?: readonly string[];
|
||||
readonly extensionWorkspaceTrustRequest?: { readonly [extensionId: string]: ExtensionWorkspaceTrustRequest };
|
||||
|
||||
readonly msftInternalDomains?: string[];
|
||||
readonly linkProtectionTrustedDomains?: readonly string[];
|
||||
|
|
|
@ -307,18 +307,6 @@ export function isAuthenticaionProviderExtension(manifest: IExtensionManifest):
|
|||
return manifest.contributes && manifest.contributes.authentication ? manifest.contributes.authentication.length > 0 : false;
|
||||
}
|
||||
|
||||
export function getExtensionWorkspaceTrustRequestType(manifest: IExtensionManifest): ExtensionWorkspaceTrustRequestType {
|
||||
if (manifest.workspaceTrust?.request !== undefined) {
|
||||
return manifest.workspaceTrust.request;
|
||||
}
|
||||
|
||||
if (!manifest.main) {
|
||||
return 'never';
|
||||
}
|
||||
|
||||
return 'onStart';
|
||||
}
|
||||
|
||||
export interface IScannedExtension {
|
||||
readonly identifier: IExtensionIdentifier;
|
||||
readonly location: URI;
|
||||
|
|
|
@ -20,12 +20,13 @@ import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteB
|
|||
import { IExtensionService, toExtension } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { getExtensionWorkspaceTrustRequestType, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { registerThemingParticipant, IColorTheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
import { foreground, listActiveSelectionForeground, listActiveSelectionBackground, listInactiveSelectionForeground, listInactiveSelectionBackground, listFocusForeground, listFocusBackground, listHoverForeground, listHoverBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IExtensionWorkspaceTrustRequestService } from 'vs/workbench/services/extensions/common/extensionWorkspaceTrustRequest';
|
||||
|
||||
export const EXTENSION_LIST_ELEMENT_HEIGHT = 62;
|
||||
|
||||
|
@ -66,6 +67,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IExtensionWorkspaceTrustRequestService private readonly extensionWorkspaceTrustRequestService: IExtensionWorkspaceTrustRequestService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||
) { }
|
||||
|
||||
|
@ -205,7 +207,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||
|
||||
if (extension.local?.manifest.workspaceTrust?.request) {
|
||||
const trustRequirement = extension.local.manifest.workspaceTrust;
|
||||
const requestType = getExtensionWorkspaceTrustRequestType(extension.local.manifest);
|
||||
const requestType = this.extensionWorkspaceTrustRequestService.getExtensionWorkspaceTrustRequestType(extension.local.manifest);
|
||||
if (requestType !== 'never' && trustRequirement.request !== 'never') {
|
||||
data.workspaceTrustDescription.textContent = trustRequirement.description;
|
||||
} else if (requestType === 'onStart') {
|
||||
|
|
|
@ -37,7 +37,7 @@ import { alert } from 'vs/base/browser/ui/aria/aria';
|
|||
import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IAction, Action, Separator, ActionRunner } from 'vs/base/common/actions';
|
||||
import { ExtensionIdentifier, getExtensionWorkspaceTrustRequestType, IExtensionDescription, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionIdentifier, IExtensionDescription, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon';
|
||||
|
@ -48,6 +48,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
|
|||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { IExtensionWorkspaceTrustRequestService } from 'vs/workbench/services/extensions/common/extensionWorkspaceTrustRequest';
|
||||
|
||||
// Extensions that are automatically classified as Programming Language extensions, but should be Feature extensions
|
||||
const FORCE_FEATURE_EXTENSIONS = ['vscode.git', 'vscode.search-result'];
|
||||
|
@ -118,6 +119,7 @@ export class ExtensionsListView extends ViewPane {
|
|||
@IWorkspaceContextService protected contextService: IWorkspaceContextService,
|
||||
@IExperimentService private readonly experimentService: IExperimentService,
|
||||
@IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IExtensionWorkspaceTrustRequestService private readonly extensionWorkspaceTrustRequestService: IExtensionWorkspaceTrustRequestService,
|
||||
@IWorkbenchExtensionManagementService protected readonly extensionManagementService: IWorkbenchExtensionManagementService,
|
||||
@IProductService protected readonly productService: IProductService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
|
@ -559,15 +561,15 @@ export class ExtensionsListView extends ViewPane {
|
|||
|
||||
value = value.replace(/@trustRequired/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase();
|
||||
|
||||
const result = local.filter(extension => extension.local && getExtensionWorkspaceTrustRequestType(extension.local.manifest) !== 'never' && (extension.name.toLowerCase().indexOf(value) > -1 || extension.displayName.toLowerCase().indexOf(value) > -1));
|
||||
const result = local.filter(extension => extension.local && this.extensionWorkspaceTrustRequestService.getExtensionWorkspaceTrustRequestType(extension.local.manifest) !== 'never' && (extension.name.toLowerCase().indexOf(value) > -1 || extension.displayName.toLowerCase().indexOf(value) > -1));
|
||||
|
||||
if (onStartOnly) {
|
||||
const onStartExtensions = result.filter(extension => extension.local && getExtensionWorkspaceTrustRequestType(extension.local.manifest) === 'onStart');
|
||||
const onStartExtensions = result.filter(extension => extension.local && this.extensionWorkspaceTrustRequestService.getExtensionWorkspaceTrustRequestType(extension.local.manifest) === 'onStart');
|
||||
return this.sortExtensions(onStartExtensions, options);
|
||||
}
|
||||
|
||||
if (onDemandOnly) {
|
||||
const onDemandExtensions = result.filter(extension => extension.local && getExtensionWorkspaceTrustRequestType(extension.local.manifest) === 'onDemand');
|
||||
const onDemandExtensions = result.filter(extension => extension.local && this.extensionWorkspaceTrustRequestService.getExtensionWorkspaceTrustRequestType(extension.local.manifest) === 'onDemand');
|
||||
return this.sortExtensions(onDemandExtensions, options);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarA
|
|||
import { IEditorRegistry, Extensions as EditorExtensions, EditorDescriptor } from 'vs/workbench/browser/editor';
|
||||
import { WorkspaceTrustEditor } from 'vs/workbench/contrib/workspace/browser/workspaceTrustEditor';
|
||||
import { WorkspaceTrustEditorInput } from 'vs/workbench/services/workspaces/browser/workspaceTrustEditorInput';
|
||||
import { WorkspaceTrustContext, WORKSPACE_TRUST_ENABLED } from 'vs/workbench/services/workspaces/common/workspaceTrust';
|
||||
import { WorkspaceTrustContext, WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_EXTENSION_REQUEST } from 'vs/workbench/services/workspaces/common/workspaceTrust';
|
||||
import { EditorInput, Extensions as EditorInputExtensions, IEditorInputSerializer, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
|
@ -423,6 +423,31 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
|
|||
default: false,
|
||||
included: !isWeb,
|
||||
description: localize('workspace.trust.description', "Controls whether or not workspace trust is enabled within VS Code."),
|
||||
},
|
||||
[WORKSPACE_TRUST_EXTENSION_REQUEST]: {
|
||||
type: 'object',
|
||||
markdownDescription: localize('security.workspace.trust.extensionRequest', "Override the workspace trust request of an extension. Extensions using `never` will always be enabled. Extensions using `onDemand` will always be enabled, and the extension will request for workspace trust only when necessary. Extensions using `onStart` will only be enabled only when the workspace is trusted."),
|
||||
patternProperties: {
|
||||
'([a-z0-9A-Z][a-z0-9\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\-A-Z]*)$': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'request': {
|
||||
type: 'string',
|
||||
enum: ['never', 'onDemand', 'onStart'],
|
||||
enumDescriptions: [
|
||||
localize('security.workspace.trust.extensionRequest.request.never', "Extension will always be enabled."),
|
||||
localize('security.workspace.trust.extensionRequest.request.onDemand', "Extension will always be enabled, and the extension will request for workspace trust only when necessary."),
|
||||
localize('security.workspace.trust.extensionRequest.request.onStart', "Extension will only be enabled only when the workspace is trusted."),
|
||||
],
|
||||
description: localize('security.workspace.trust.extensionRequest.request', "Defines the workspace trust request setting for the extension."),
|
||||
},
|
||||
'version': {
|
||||
type: 'string',
|
||||
description: localize('security.workspace.trust.extensionRequest.version', "Defines the version of the extension for which the override should be applied. If not specified, the override will be applied independent of the extension version."),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -24,7 +24,7 @@ import { localize } from 'vs/nls';
|
|||
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { ExtensionWorkspaceTrustRequestType, getExtensionWorkspaceTrustRequestType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionWorkspaceTrustRequestType } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IPromptChoiceWithMenu } from 'vs/platform/notification/common/notification';
|
||||
import { Link } from 'vs/platform/opener/browser/link';
|
||||
|
@ -43,6 +43,7 @@ import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/com
|
|||
import { getInstalledExtensions, IExtensionStatus } from 'vs/workbench/contrib/extensions/common/extensionsUtils';
|
||||
import { trustedForegroundColor, untrustedForegroundColor } from 'vs/workbench/contrib/workspace/browser/workspaceTrustColors';
|
||||
import { IWorkspaceTrustSettingChangeEvent, WorkspaceTrustSettingArrayRenderer, WorkspaceTrustTree, WorkspaceTrustTreeModel } from 'vs/workbench/contrib/workspace/browser/workspaceTrustTree';
|
||||
import { IExtensionWorkspaceTrustRequestService } from 'vs/workbench/services/extensions/common/extensionWorkspaceTrustRequest';
|
||||
import { WorkspaceTrustEditorInput } from 'vs/workbench/services/workspaces/browser/workspaceTrustEditorInput';
|
||||
|
||||
const untrustedIcon = registerCodicon('workspace-untrusted-icon', Codicon.workspaceUntrusted);
|
||||
|
@ -80,6 +81,7 @@ export class WorkspaceTrustEditor extends EditorPane {
|
|||
@IStorageService storageService: IStorageService,
|
||||
@IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService,
|
||||
@IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IExtensionWorkspaceTrustRequestService private readonly extensionWorkspaceTrustRequestService: IExtensionWorkspaceTrustRequestService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||
@IDialogService private readonly dialogService: IDialogService,
|
||||
|
@ -227,7 +229,7 @@ export class WorkspaceTrustEditor extends EditorPane {
|
|||
}
|
||||
|
||||
private getExtensionCountByTrustRequestType(extensions: IExtensionStatus[], trustRequestType: ExtensionWorkspaceTrustRequestType): number {
|
||||
const filtered = extensions.filter(ext => getExtensionWorkspaceTrustRequestType(ext.local.manifest) === trustRequestType);
|
||||
const filtered = extensions.filter(ext => this.extensionWorkspaceTrustRequestService.getExtensionWorkspaceTrustRequestType(ext.local.manifest) === trustRequestType);
|
||||
const set = new Set<string>();
|
||||
for (const ext of filtered) {
|
||||
set.add(ext.identifier.id);
|
||||
|
|
|
@ -12,7 +12,7 @@ import { areSameExtensions } from 'vs/platform/extensionManagement/common/extens
|
|||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { getExtensionWorkspaceTrustRequestType, IExtension, isAuthenticaionProviderExtension, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtension, isAuthenticaionProviderExtension, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ExtensionKindController } from 'vs/workbench/services/extensions/common/extensionsUtil';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
|
@ -27,6 +27,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host';
|
|||
import { IExtensionBisectService } from 'vs/workbench/services/extensionManagement/browser/extensionBisect';
|
||||
import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService, WorkspaceTrustState, WorkspaceTrustStateChangeEvent } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { Promises } from 'vs/base/common/async';
|
||||
import { IExtensionWorkspaceTrustRequestService } from 'vs/workbench/services/extensions/common/extensionWorkspaceTrustRequest';
|
||||
|
||||
const SOURCE = 'IWorkbenchExtensionEnablementService';
|
||||
|
||||
|
@ -48,6 +49,7 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench
|
|||
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||
@IExtensionWorkspaceTrustRequestService private readonly extensionWorkspaceTrustRequestService: IExtensionWorkspaceTrustRequestService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IProductService productService: IProductService,
|
||||
|
@ -277,7 +279,7 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench
|
|||
private _isDisabledByTrustRequirement(extension: IExtension): boolean {
|
||||
const workspaceTrustState = this.workspaceTrustManagementService.getWorkspaceTrustState();
|
||||
|
||||
if (getExtensionWorkspaceTrustRequestType(extension.manifest) === 'onStart') {
|
||||
if (this.extensionWorkspaceTrustRequestService.getExtensionWorkspaceTrustRequestType(extension.manifest) === 'onStart') {
|
||||
if (workspaceTrustState !== WorkspaceTrustState.Trusted) {
|
||||
this._addToWorkspaceDisabledExtensionsByTrustRequirement(extension);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent, IExtensionIdentifier, DidUninstallExtensionEvent, IReportedExtension, IGalleryMetadata, IExtensionGalleryService, InstallOptions, UninstallOptions, INSTALL_ERROR_NOT_SUPPORTED
|
||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionManagementServer, IExtensionManagementServerService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionType, isLanguagePackExtension, IExtensionManifest, getExtensionWorkspaceTrustRequestType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionType, isLanguagePackExtension, IExtensionManifest } from 'vs/platform/extensions/common/extensions';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
@ -26,6 +26,7 @@ import { canceled } from 'vs/base/common/errors';
|
|||
import { IUserDataAutoSyncEnablementService, IUserDataSyncResourceEnablementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { Promises } from 'vs/base/common/async';
|
||||
import { IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { IExtensionWorkspaceTrustRequestService } from 'vs/workbench/services/extensions/common/extensionWorkspaceTrustRequest';
|
||||
|
||||
export class ExtensionManagementService extends Disposable implements IWorkbenchExtensionManagementService {
|
||||
|
||||
|
@ -43,6 +44,7 @@ export class ExtensionManagementService extends Disposable implements IWorkbench
|
|||
constructor(
|
||||
@IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
|
||||
@IExtensionWorkspaceTrustRequestService private readonly extensionWorkspaceTrustRequestService: IExtensionWorkspaceTrustRequestService,
|
||||
@IConfigurationService protected readonly configurationService: IConfigurationService,
|
||||
@IProductService protected readonly productService: IProductService,
|
||||
@IDownloadService protected readonly downloadService: IDownloadService,
|
||||
|
@ -361,7 +363,7 @@ export class ExtensionManagementService extends Disposable implements IWorkbench
|
|||
}
|
||||
|
||||
protected async checkForWorkspaceTrust(manifest: IExtensionManifest): Promise<void> {
|
||||
if (getExtensionWorkspaceTrustRequestType(manifest) === 'onStart') {
|
||||
if (this.extensionWorkspaceTrustRequestService.getExtensionWorkspaceTrustRequestType(manifest) === 'onStart') {
|
||||
const trustState = await this.workspaceTrustRequestService.requestWorkspaceTrust({
|
||||
modal: true,
|
||||
message: localize('extensionInstallWorkspaceTrustMessage', "Enabling this extension requires a trusted workspace."),
|
||||
|
|
|
@ -18,6 +18,7 @@ import { joinPath } from 'vs/base/common/resources';
|
|||
import { IUserDataAutoSyncEnablementService, IUserDataSyncResourceEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { IExtensionWorkspaceTrustRequestService } from 'vs/workbench/services/extensions/common/extensionWorkspaceTrustRequest';
|
||||
|
||||
export class ExtensionManagementService extends BaseExtensionManagementService {
|
||||
|
||||
|
@ -25,6 +26,7 @@ export class ExtensionManagementService extends BaseExtensionManagementService {
|
|||
@INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService,
|
||||
@IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IExtensionGalleryService extensionGalleryService: IExtensionGalleryService,
|
||||
@IExtensionWorkspaceTrustRequestService extensionWorkspaceTrustRequestService: IExtensionWorkspaceTrustRequestService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IProductService productService: IProductService,
|
||||
@IDownloadService downloadService: IDownloadService,
|
||||
|
@ -33,7 +35,7 @@ export class ExtensionManagementService extends BaseExtensionManagementService {
|
|||
@IDialogService dialogService: IDialogService,
|
||||
@IWorkspaceTrustRequestService workspaceTrustRequestService: IWorkspaceTrustRequestService
|
||||
) {
|
||||
super(extensionManagementServerService, extensionGalleryService, configurationService, productService, downloadService, userDataAutoSyncEnablementService, userDataSyncResourceEnablementService, dialogService, workspaceTrustRequestService);
|
||||
super(extensionManagementServerService, extensionGalleryService, extensionWorkspaceTrustRequestService, configurationService, productService, downloadService, userDataAutoSyncEnablementService, userDataSyncResourceEnablementService, dialogService, workspaceTrustRequestService);
|
||||
}
|
||||
|
||||
protected async override installVSIX(vsix: URI, server: IExtensionManagementServer): Promise<ILocalExtension> {
|
||||
|
|
|
@ -12,7 +12,7 @@ import { Emitter } from 'vs/base/common/event';
|
|||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IStorageService, InMemoryStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IExtensionContributions, ExtensionType, IExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtensionContributions, ExtensionType, IExtension, IExtensionManifest, ExtensionWorkspaceTrustRequestType } from 'vs/platform/extensions/common/extensions';
|
||||
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
@ -32,6 +32,7 @@ import { mock } from 'vs/base/test/common/mock';
|
|||
import { IExtensionBisectService } from 'vs/workbench/services/extensionManagement/browser/extensionBisect';
|
||||
import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { TestWorkspaceTrustManagementService, TestWorkspaceTrustRequestService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService';
|
||||
import { IExtensionWorkspaceTrustRequestService } from 'vs/workbench/services/extensions/common/extensionWorkspaceTrustRequest';
|
||||
|
||||
function createStorageService(instantiationService: TestInstantiationService): IStorageService {
|
||||
let service = instantiationService.get(IStorageService);
|
||||
|
@ -58,6 +59,7 @@ export class TestExtensionEnablementService extends ExtensionEnablementService {
|
|||
instantiationService.get(IWorkspaceContextService),
|
||||
instantiationService.get(IWorkbenchEnvironmentService) || instantiationService.stub(IWorkbenchEnvironmentService, { configuration: Object.create(null) } as IWorkbenchEnvironmentService),
|
||||
extensionManagementService,
|
||||
new class extends mock<IExtensionWorkspaceTrustRequestService>() { getExtensionWorkspaceTrustRequestType(manifest: IExtensionManifest): ExtensionWorkspaceTrustRequestType { return 'never'; } },
|
||||
instantiationService.get(IConfigurationService),
|
||||
extensionManagementServerService,
|
||||
productService,
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ExtensionWorkspaceTrustRequest } from 'vs/base/common/product';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionIdentifier, ExtensionWorkspaceTrustRequestType, IExtensionManifest } from 'vs/platform/extensions/common/extensions';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { WORKSPACE_TRUST_EXTENSION_REQUEST } from 'vs/workbench/services/workspaces/common/workspaceTrust';
|
||||
|
||||
export const IExtensionWorkspaceTrustRequestService = createDecorator<IExtensionWorkspaceTrustRequestService>('extensionWorkspaceTrustRequestService');
|
||||
|
||||
export interface IExtensionWorkspaceTrustRequestService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
getExtensionWorkspaceTrustRequestType(manifest: IExtensionManifest): ExtensionWorkspaceTrustRequestType;
|
||||
}
|
||||
|
||||
export class ExtensionWorkspaceTrustRequestService extends Disposable implements IExtensionWorkspaceTrustRequestService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private readonly _configuredExtensionWorkspaceTrustRequestMap: Map<string, { request: ExtensionWorkspaceTrustRequestType, version?: string }>;
|
||||
private readonly _productExtensionWorkspaceTrustRequestMap: Map<string, ExtensionWorkspaceTrustRequest>;
|
||||
|
||||
constructor(
|
||||
@IProductService productService: IProductService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IWorkspaceTrustManagementService private readonly _workspaceTrustManagementService: IWorkspaceTrustManagementService
|
||||
) {
|
||||
super();
|
||||
|
||||
// Settings.json
|
||||
this._configuredExtensionWorkspaceTrustRequestMap = new Map<string, { request: ExtensionWorkspaceTrustRequestType, version?: string }>();
|
||||
const configuredExtensionWorkspaceTrustRequests = configurationService.inspect<{ [key: string]: { request: ExtensionWorkspaceTrustRequestType, version?: string } }>(WORKSPACE_TRUST_EXTENSION_REQUEST).userValue || {};
|
||||
for (const id of Object.keys(configuredExtensionWorkspaceTrustRequests)) {
|
||||
this._configuredExtensionWorkspaceTrustRequestMap.set(ExtensionIdentifier.toKey(id), configuredExtensionWorkspaceTrustRequests[id]);
|
||||
}
|
||||
|
||||
// Products.json
|
||||
this._productExtensionWorkspaceTrustRequestMap = new Map<string, ExtensionWorkspaceTrustRequest>();
|
||||
if (productService.extensionWorkspaceTrustRequest) {
|
||||
for (const id of Object.keys(productService.extensionWorkspaceTrustRequest)) {
|
||||
this._productExtensionWorkspaceTrustRequestMap.set(ExtensionIdentifier.toKey(id), productService.extensionWorkspaceTrustRequest[id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getConfiguredExtensionWorkspaceTrustRequest(manifest: IExtensionManifest): ExtensionWorkspaceTrustRequestType | undefined {
|
||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||
const extensionWorkspaceTrustRequest = this._configuredExtensionWorkspaceTrustRequestMap.get(ExtensionIdentifier.toKey(extensionId));
|
||||
|
||||
if (extensionWorkspaceTrustRequest && (extensionWorkspaceTrustRequest.version === undefined || extensionWorkspaceTrustRequest.version === manifest.version)) {
|
||||
return extensionWorkspaceTrustRequest.request;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getProductExtensionWorkspaceTrustRequest(manifest: IExtensionManifest): ExtensionWorkspaceTrustRequest | undefined {
|
||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||
return this._productExtensionWorkspaceTrustRequestMap.get(ExtensionIdentifier.toKey(extensionId));
|
||||
}
|
||||
|
||||
getExtensionWorkspaceTrustRequestType(manifest: IExtensionManifest): ExtensionWorkspaceTrustRequestType {
|
||||
// Workspace trust feature is disabled, or extension has no entry point
|
||||
if (!this._workspaceTrustManagementService.isWorkspaceTrustEnabled() || !manifest.main) {
|
||||
return 'never';
|
||||
}
|
||||
|
||||
// Get extension workspace trust requirements from settings.json
|
||||
const configuredWorkspaceTrustRequest = this.getConfiguredExtensionWorkspaceTrustRequest(manifest);
|
||||
|
||||
// Get extension workspace trust requirements from product.json
|
||||
const productWorkspaceTrustRequest = this.getProductExtensionWorkspaceTrustRequest(manifest);
|
||||
|
||||
// Use settings.json override value if it exists
|
||||
if (configuredWorkspaceTrustRequest) {
|
||||
return configuredWorkspaceTrustRequest;
|
||||
}
|
||||
|
||||
// Use product.json override value if it exists
|
||||
if (productWorkspaceTrustRequest?.override) {
|
||||
return productWorkspaceTrustRequest.override;
|
||||
}
|
||||
|
||||
// Use extension manifest value if it exists
|
||||
if (manifest.workspaceTrust?.request !== undefined) {
|
||||
return manifest.workspaceTrust.request;
|
||||
}
|
||||
|
||||
// Use product.json default value if it exists
|
||||
if (productWorkspaceTrustRequest?.default) {
|
||||
return productWorkspaceTrustRequest.default;
|
||||
}
|
||||
|
||||
return 'onStart';
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IExtensionWorkspaceTrustRequestService, ExtensionWorkspaceTrustRequestService);
|
|
@ -0,0 +1,126 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { ExtensionWorkspaceTrustRequestService } from 'vs/workbench/services/extensions/common/extensionWorkspaceTrustRequest';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { WorkspaceTrustManagementService } from 'vs/workbench/services/workspaces/common/workspaceTrust';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { ExtensionWorkspaceTrustRequestType, IExtensionManifest } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
|
||||
suite('ExtensionWorkspaceTrustRequestService', () => {
|
||||
let testObject: ExtensionWorkspaceTrustRequestService;
|
||||
let instantiationService: TestInstantiationService;
|
||||
let testConfigurationService: TestConfigurationService;
|
||||
|
||||
setup(() => {
|
||||
instantiationService = new TestInstantiationService();
|
||||
|
||||
testConfigurationService = new TestConfigurationService();
|
||||
instantiationService.stub(IConfigurationService, testConfigurationService);
|
||||
});
|
||||
|
||||
teardown(() => testObject.dispose());
|
||||
|
||||
function assertWorkspaceTrustRequest(extensionMaifest: IExtensionManifest, expected: ExtensionWorkspaceTrustRequestType): void {
|
||||
testObject = instantiationService.createInstance(ExtensionWorkspaceTrustRequestService);
|
||||
const workspaceTrustRequest = testObject.getExtensionWorkspaceTrustRequestType(extensionMaifest);
|
||||
|
||||
assert.strictEqual(workspaceTrustRequest, expected);
|
||||
}
|
||||
|
||||
test('test extension workspace trust request when main entry point is missing', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, getWorkspaceTrustManagementService(true));
|
||||
|
||||
const extensionMaifest = getExtensionManifest();
|
||||
assertWorkspaceTrustRequest(extensionMaifest, 'never');
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when workspace trust is disabled', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, getWorkspaceTrustManagementService(false));
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
|
||||
assertWorkspaceTrustRequest(extensionMaifest, 'never');
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override exists in settings.json', async () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, getWorkspaceTrustManagementService(true));
|
||||
|
||||
await testConfigurationService.setUserConfiguration('security', { workspace: { trust: { extensionRequest: { 'pub.a': { request: 'never' } } } } });
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', workspaceTrust: { request: 'onDemand' } });
|
||||
assertWorkspaceTrustRequest(extensionMaifest, 'never');
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override for the version exists in settings.json', async () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, getWorkspaceTrustManagementService(true));
|
||||
|
||||
await testConfigurationService.setUserConfiguration('security', { workspace: { trust: { extensionRequest: { 'pub.a': { request: 'never', version: '1.0.0' } } } } });
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', workspaceTrust: { request: 'onDemand' } });
|
||||
assertWorkspaceTrustRequest(extensionMaifest, 'never');
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override for a different version exists in settings.json', async () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, getWorkspaceTrustManagementService(true));
|
||||
|
||||
await testConfigurationService.setUserConfiguration('security', { workspace: { trust: { extensionRequest: { 'pub.a': { request: 'never', version: '2.0.0' } } } } });
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', workspaceTrust: { request: 'onDemand' } });
|
||||
assertWorkspaceTrustRequest(extensionMaifest, 'onDemand');
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when default exists in product.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{ extensionWorkspaceTrustRequest: { 'pub.a': { default: 'never' } } });
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, getWorkspaceTrustManagementService(true));
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
|
||||
assertWorkspaceTrustRequest(extensionMaifest, 'never');
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override exists in product.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{ extensionWorkspaceTrustRequest: { 'pub.a': { override: 'onDemand' } } });
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, getWorkspaceTrustManagementService(true));
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', workspaceTrust: { request: 'never' } });
|
||||
assertWorkspaceTrustRequest(extensionMaifest, 'onDemand');
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when value exists in package.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, getWorkspaceTrustManagementService(true));
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', workspaceTrust: { request: 'onDemand' } });
|
||||
assertWorkspaceTrustRequest(extensionMaifest, 'onDemand');
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when no value exists in package.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, getWorkspaceTrustManagementService(true));
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
|
||||
assertWorkspaceTrustRequest(extensionMaifest, 'onStart');
|
||||
});
|
||||
});
|
||||
|
||||
function getExtensionManifest(properties: any = {}): IExtensionManifest {
|
||||
return Object.create({
|
||||
name: 'a',
|
||||
publisher: 'pub',
|
||||
version: '1.0.0',
|
||||
...properties
|
||||
}) as IExtensionManifest;
|
||||
}
|
||||
|
||||
function getWorkspaceTrustManagementService(isEnabled: boolean): WorkspaceTrustManagementService {
|
||||
return new class extends mock<WorkspaceTrustManagementService>() { isWorkspaceTrustEnabled() { return isEnabled; } };
|
||||
}
|
|
@ -17,6 +17,7 @@ import { WorkspaceTrustRequestOptions, IWorkspaceTrustManagementService, IWorksp
|
|||
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
|
||||
|
||||
export const WORKSPACE_TRUST_ENABLED = 'security.workspace.trust.enabled';
|
||||
export const WORKSPACE_TRUST_EXTENSION_REQUEST = 'security.workspace.trust.extensionRequest';
|
||||
export const WORKSPACE_TRUST_STORAGE_KEY = 'content.trust.model.key';
|
||||
|
||||
export const WorkspaceTrustContext = {
|
||||
|
|
Loading…
Reference in a new issue