Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workspace trust - remote workspace #124617

Merged
merged 10 commits into from May 26, 2021
8 changes: 5 additions & 3 deletions src/vs/platform/workspace/common/workspaceTrust.ts
Expand Up @@ -40,16 +40,18 @@ export interface IWorkspaceTrustManagementService {

onDidChangeTrust: WorkspaceTrustChangeEvent;
onDidChangeTrustedFolders: Event<void>;

onDidInitiateWorkspaceTrustRequestOnStartup: Event<void>;
get acceptsOutOfWorkspaceFiles(): boolean;
set acceptsOutOfWorkspaceFiles(value: boolean);
addWorkspaceTrustTransitionParticipant(participant: IWorkspaceTrustTransitionParticipant): IDisposable;
initializeWorkspaceTrust(): Promise<void>;
isWorkpaceTrusted(): boolean;
canSetParentFolderTrust(): boolean;
setParentFolderTrust(trusted: boolean): Promise<void>;
canSetWorkspaceTrust(): boolean;
canSetWorkspaceTrust(): Promise<boolean>;
recalculateWorkspaceTrust(): Promise<void>;
setWorkspaceTrust(trusted: boolean): Promise<void>;
getUriTrustInfo(folder: URI): IWorkspaceTrustUriInfo;
getUriTrustInfo(folder: URI): Promise<IWorkspaceTrustUriInfo>;
setUrisTrust(folders: URI[], trusted: boolean): Promise<void>;
getTrustedFolders(): URI[];
setTrustedFolders(folders: URI[]): Promise<void>;
Expand Down
7 changes: 5 additions & 2 deletions src/vs/workbench/browser/web.main.ts
Expand Up @@ -60,7 +60,7 @@ import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/ur
import { UriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentityService';
import { BrowserWindow } from 'vs/workbench/browser/window';
import { ITimerService } from 'vs/workbench/services/timer/browser/timerService';
import { WorkspaceTrustManagementService } from 'vs/workbench/services/workspaces/common/workspaceTrust';
import { RemoteWorkspaceTrustManagementService, WorkspaceTrustManagementService } from 'vs/workbench/services/workspaces/common/workspaceTrust';
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
import { HTMLFileSystemProvider } from 'vs/platform/files/browser/htmlFileSystemProvider';
import { IOpenerService } from 'vs/platform/opener/common/opener';
Expand Down Expand Up @@ -210,7 +210,10 @@ class BrowserMain extends Disposable {
]);

// Workspace Trust Service
const workspaceTrustManagementService = new WorkspaceTrustManagementService(configurationService, environmentService, storageService, uriIdentityService, configurationService);
const workspaceTrustManagementService = !environmentService.remoteAuthority ?
new WorkspaceTrustManagementService(configurationService, storageService, uriIdentityService, environmentService, configurationService) :
new RemoteWorkspaceTrustManagementService(configurationService, storageService, uriIdentityService, environmentService, configurationService, remoteAuthorityResolverService);
await workspaceTrustManagementService.initializeWorkspaceTrust();
serviceCollection.set(IWorkspaceTrustManagementService, workspaceTrustManagementService);

// Update workspace trust so that configuration is updated accordingly
Expand Down
Expand Up @@ -4,34 +4,39 @@
*--------------------------------------------------------------------------------------------*/

import { Disposable } from 'vs/base/common/lifecycle';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkspaceTrustManagementService, IWorkspaceTrustTransitionParticipant } from 'vs/platform/workspace/common/workspaceTrust';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { isWorkspaceTrustEnabled } from 'vs/workbench/services/workspaces/common/workspaceTrust';

export class ExtensionEnablementWorkspaceTrustTransitionParticipant extends Disposable implements IWorkbenchContribution {
constructor(
@IConfigurationService configurationService: IConfigurationService,
@IExtensionService extensionService: IExtensionService,
@IWorkbenchExtensionEnablementService extensionEnablementService: IWorkbenchExtensionEnablementService,
@IWorkspaceTrustManagementService workspaceTrustManagementService: IWorkspaceTrustManagementService,
) {
super();

const workspaceTrustTransitionParticipant = new class implements IWorkspaceTrustTransitionParticipant {
async participate(trusted: boolean): Promise<void> {
if (trusted) {
// Untrusted -> Trusted
await extensionEnablementService.updateEnablementByWorkspaceTrustRequirement();
} else {
// Trusted -> Untrusted
extensionService.stopExtensionHosts();
await extensionEnablementService.updateEnablementByWorkspaceTrustRequirement();
extensionService.startExtensionHosts();
if (!isWorkspaceTrustEnabled(configurationService)) {
const workspaceTrustTransitionParticipant = new class implements IWorkspaceTrustTransitionParticipant {
async participate(trusted: boolean): Promise<void> {
if (trusted) {
// Untrusted -> Trusted
await extensionEnablementService.updateEnablementByWorkspaceTrustRequirement();
} else {
// Trusted -> Untrusted
extensionService.stopExtensionHosts();
await extensionEnablementService.updateEnablementByWorkspaceTrustRequirement();
extensionService.startExtensionHosts();
}
}
}
};
};

// Execute BEFORE the workspace trust transition completes
this._register(workspaceTrustManagementService.addWorkspaceTrustTransitionParticipant(workspaceTrustTransitionParticipant));
// Execute BEFORE the workspace trust transition completes
this._register(workspaceTrustManagementService.addWorkspaceTrustTransitionParticipant(workspaceTrustTransitionParticipant));
}
}
}
Expand Up @@ -159,12 +159,17 @@ export class WorkspaceTrustRequestHandler extends Disposable implements IWorkben
this.storageService.store(STARTUP_PROMPT_SHOWN_KEY, true, StorageScope.WORKSPACE, StorageTarget.MACHINE);
}

private showModalOnStart(): void {
private async showModalOnStart(): Promise<void> {
if (this.workspaceTrustManagementService.isWorkpaceTrusted()) {
this.updateWorkbenchIndicators(true);
return;
}

// Don't show modal prompt if workspace trust cannot be changed
if (!(await this.workspaceTrustManagementService.canSetWorkspaceTrust())) {
return;
}

// Don't show modal prompt for virtual workspaces by default
if (getVirtualWorkspaceScheme(this.workspaceContextService.getWorkspace()) !== undefined) {
this.updateWorkbenchIndicators(false);
Expand Down Expand Up @@ -318,7 +323,7 @@ export class WorkspaceTrustRequestHandler extends Disposable implements IWorkben
};
}

private setEmptyWorkspaceTrustState(): void {
private async setEmptyWorkspaceTrustState(): Promise<void> {
if (this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY) {
return;
}
Expand All @@ -328,7 +333,9 @@ export class WorkspaceTrustRequestHandler extends Disposable implements IWorkben

if (openFiles.length) {
// If all open files are trusted, transition to a trusted workspace
if (openFiles.map(uri => this.workspaceTrustManagementService.getUriTrustInfo(uri!).trusted).every(trusted => trusted)) {
const openFilesTrustInfo = await Promise.all(openFiles.map(uri => this.workspaceTrustManagementService.getUriTrustInfo(uri!)));

if (openFilesTrustInfo.map(info => info.trusted).every(trusted => trusted)) {
this.workspaceTrustManagementService.setWorkspaceTrust(true);
}
} else {
Expand Down Expand Up @@ -366,6 +373,10 @@ export class WorkspaceTrustRequestHandler extends Disposable implements IWorkben
}

private registerListeners(): void {
this._register(this.workspaceTrustManagementService.onDidInitiateWorkspaceTrustRequestOnStartup(() => {
this.showModalOnStart();
}));

this._register(this.workspaceTrustRequestService.onDidInitiateWorkspaceTrustRequest(async requestOptions => {
// Message
const defaultMessage = localize('immediateTrustRequestMessage', "A feature you are trying to use may be a security risk if you do not trust the source of the files or folders you currently have open.");
Expand Down Expand Up @@ -428,8 +439,9 @@ export class WorkspaceTrustRequestHandler extends Disposable implements IWorkben
return e.join(new Promise(async resolve => {
// Workspace is trusted and there are added/changed folders
if (trusted && (e.changes.added.length || e.changes.changed.length)) {
const addedFoldersTrustInfo = e.changes.added.map(folder => this.workspaceTrustManagementService.getUriTrustInfo(folder.uri));
if (!addedFoldersTrustInfo.map(i => i.trusted).every(trusted => trusted)) {
const addedFoldersTrustInfo = await Promise.all(e.changes.added.map(folder => this.workspaceTrustManagementService.getUriTrustInfo(folder.uri)));

if (!addedFoldersTrustInfo.map(info => info.trusted).every(trusted => trusted)) {
const result = await this.dialogService.show(
Severity.Info,
localize('addWorkspaceFolderMessage', "Do you trust the authors of the files in this folder?"),
Expand Down Expand Up @@ -618,7 +630,7 @@ class WorkspaceTrustTelemetryContribution extends Disposable implements IWorkben
});
}

private logWorkspaceTrustChangeEvent(isTrusted: boolean): void {
private async logWorkspaceTrustChangeEvent(isTrusted: boolean): Promise<void> {
if (!isWorkspaceTrustEnabled(this.configurationService)) {
return;
}
Expand Down Expand Up @@ -664,7 +676,7 @@ class WorkspaceTrustTelemetryContribution extends Disposable implements IWorkben
};

for (const folder of this.workspaceContextService.getWorkspace().folders) {
const { trusted, uri } = this.workspaceTrustManagementService.getUriTrustInfo(folder.uri);
const { trusted, uri } = await this.workspaceTrustManagementService.getUriTrustInfo(folder.uri);
if (!trusted) {
continue;
}
Expand Down
Expand Up @@ -779,7 +779,7 @@ export class WorkspaceTrustEditor extends EditorPane {
this.affectedFeaturesContainer = append(parent, $('.workspace-trust-features'));
}

private renderAffectedFeatures(numSettings: number, numExtensions: number): void {
private async renderAffectedFeatures(numSettings: number, numExtensions: number): Promise<void> {
clearNode(this.affectedFeaturesContainer);
const trustedContainer = append(this.affectedFeaturesContainer, $('.workspace-trust-limitations.trusted'));
const [trustedTitle, trustedSubTitle] = this.getFeaturesHeaderText(true);
Expand All @@ -803,13 +803,13 @@ export class WorkspaceTrustEditor extends EditorPane {
], xListIcon.classNamesArray);

if (this.workspaceTrustManagementService.isWorkpaceTrusted()) {
if (this.workspaceTrustManagementService.canSetWorkspaceTrust()) {
if (await this.workspaceTrustManagementService.canSetWorkspaceTrust()) {
this.addDontTrustButtonToElement(untrustedContainer);
} else {
this.addTrustedTextToElement(untrustedContainer);
}
} else {
if (this.workspaceTrustManagementService.canSetWorkspaceTrust()) {
if (await this.workspaceTrustManagementService.canSetWorkspaceTrust()) {
this.addTrustButtonToElement(trustedContainer);
}
}
Expand Down
7 changes: 5 additions & 2 deletions src/vs/workbench/electron-sandbox/shared.desktop.main.ts
Expand Up @@ -44,7 +44,7 @@ import { ElectronIPCMainProcessService } from 'vs/platform/ipc/electron-sandbox/
import { LoggerChannelClient, LogLevelChannelClient } from 'vs/platform/log/common/logIpc';
import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc';
import { NativeLogService } from 'vs/workbench/services/log/electron-sandbox/logService';
import { WorkspaceTrustManagementService } from 'vs/workbench/services/workspaces/common/workspaceTrust';
import { RemoteWorkspaceTrustManagementService, WorkspaceTrustManagementService } from 'vs/workbench/services/workspaces/common/workspaceTrust';
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
import { registerWindowDriver } from 'vs/platform/driver/electron-sandbox/driver';

Expand Down Expand Up @@ -264,7 +264,10 @@ export abstract class SharedDesktopMain extends Disposable {
]);

// Workspace Trust Service
const workspaceTrustManagementService = new WorkspaceTrustManagementService(configurationService, environmentService, storageService, uriIdentityService, configurationService);
const workspaceTrustManagementService = !environmentService.remoteAuthority ?
new WorkspaceTrustManagementService(configurationService, storageService, uriIdentityService, environmentService, configurationService) :
new RemoteWorkspaceTrustManagementService(configurationService, storageService, uriIdentityService, environmentService, configurationService, remoteAuthorityResolverService);
await workspaceTrustManagementService.initializeWorkspaceTrust();
serviceCollection.set(IWorkspaceTrustManagementService, workspaceTrustManagementService);

// Update workspace trust so that configuration is updated accordingly
Expand Down
Expand Up @@ -43,6 +43,7 @@ import { ExtensionHostExitCode } from 'vs/workbench/services/extensions/common/e
import { updateProxyConfigurationsScope } from 'vs/platform/request/common/request';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';

export class ExtensionService extends AbstractExtensionService implements IExtensionService {

Expand Down Expand Up @@ -70,6 +71,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
@IRemoteExplorerService private readonly _remoteExplorerService: IRemoteExplorerService,
@IExtensionGalleryService private readonly _extensionGalleryService: IExtensionGalleryService,
@ILogService private readonly _logService: ILogService,
@IWorkspaceTrustManagementService private readonly _workspaceTrustManagementService: IWorkspaceTrustManagementService,
@IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService,
) {
super(
Expand Down Expand Up @@ -351,6 +353,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
return localProcessExtensionHost.getCanonicalURI(remoteAuthority, uri);
});

// Now that the canonical URI provider has been registered, we
// need to refresh workspace trust before resolving the authority
await this._workspaceTrustManagementService.recalculateWorkspaceTrust();

let resolverResult: ResolverResult;

try {
Expand Down