Skip to content

Commit

Permalink
Add localResourceRoots to webview options
Browse files Browse the repository at this point in the history
Fixes #44039

Add a new option that lets extensions override which root folders a webview can load local resources from. Defaults to allowing any resource in the workspace
  • Loading branch information
mjbvz committed Feb 21, 2018
1 parent bcbd339 commit 2d1f6d4
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 25 deletions.
20 changes: 19 additions & 1 deletion extensions/markdown/src/features/previewContentProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,10 @@ export class MarkdownPreviewWebviewManager {
const view = vscode.window.createWebview(
localize('previewTitle', 'Preview {0}', path.basename(resource.fsPath)),
viewColumn,
{ enableScripts: true });
{
enableScripts: true,
localResourceRoots: this.getLocalResourceRoots(resource)
});

this.contentProvider.provideTextDocumentContent(resource, this.previewConfigurations).then(x => view.html = x);

Expand All @@ -373,4 +376,19 @@ export class MarkdownPreviewWebviewManager {
this.webviews.set(resource.fsPath, view);
return view;
}

private getLocalResourceRoots(
resource: vscode.Uri
): vscode.Uri[] {
const folder = vscode.workspace.getWorkspaceFolder(resource);
if (folder) {
return [folder.uri];
}

if (!resource.scheme || resource.scheme === 'file') {
return [vscode.Uri.parse(path.dirname(resource.fsPath))];
}

return [];
}
}
11 changes: 10 additions & 1 deletion src/vs/vscode.proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ declare module 'vscode' {
*/
export interface WebviewOptions {
/**
* Should scripts be enabled in the webview contetn?
* Should scripts be enabled in the webview content?
*
* Defaults to false (scripts-disabled).
*/
Expand All @@ -423,6 +423,15 @@ declare module 'vscode' {
* webview content cannot be quickly saved and restored.
*/
readonly keepAlive?: boolean;

/**
* Root paths from which the webview can load local (filesystem) resources using the `vscode-workspace-resource:` scheme.
*
* Default to the root folders of the current workspace.
*
* Pass in an empty array to disallow access to any local resources.
*/
readonly localResourceRoots?: Uri[];
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/vs/workbench/api/electron-browser/mainThreadWebview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,9 @@ class WebviewEditor extends BaseWebviewEditor {

this.webview.options = {
allowScripts: input.options.enableScripts,
enableWrappedPostMessage: true
enableWrappedPostMessage: true,
useSameOriginForRoot: false,
localResourceRoots: (input && input.options.localResourceRoots) || this._contextService.getWorkspace().folders.map(x => x.uri)
};
this.webview.contents = input.html;
}
Expand All @@ -215,7 +217,6 @@ class WebviewEditor extends BaseWebviewEditor {
this._partService.getContainer(Parts.EDITOR_PART),
this.themeService,
this._environmentService,
this._contextService,
this._contextViewService,
this.contextKey,
this.findInputFocusContextKey,
Expand Down
6 changes: 2 additions & 4 deletions src/vs/workbench/parts/extensions/browser/extensionEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ import { Color } from 'vs/base/common/color';
import { WorkbenchTree } from 'vs/platform/list/browser/listService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { assign } from 'vs/base/common/objects';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { INotificationService } from 'vs/platform/notification/common/notification';

/** A context key that is set when an extension editor webview has focus. */
Expand Down Expand Up @@ -194,8 +193,7 @@ export class ExtensionEditor extends BaseEditor {
@IContextViewService private readonly contextViewService: IContextViewService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IExtensionTipsService private readonly extensionTipsService: IExtensionTipsService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService
@IEnvironmentService private readonly environmentService: IEnvironmentService

) {
super(ExtensionEditor.ID, telemetryService, themeService);
Expand Down Expand Up @@ -421,7 +419,7 @@ export class ExtensionEditor extends BaseEditor {
.then<void>(body => {
const allowedBadgeProviders = this.extensionsWorkbenchService.allowedBadgeProviders;
const webViewOptions = allowedBadgeProviders.length > 0 ? { allowScripts: false, allowSvgs: false, svgWhiteList: allowedBadgeProviders } : {};
this.activeWebview = new Webview(this.content, this.partService.getContainer(Parts.EDITOR_PART), this.themeService, this.environmentService, this.contextService, this.contextViewService, this.contextKey, this.findInputFocusContextKey, webViewOptions);
this.activeWebview = new Webview(this.content, this.partService.getContainer(Parts.EDITOR_PART), this.themeService, this.environmentService, this.contextViewService, this.contextKey, this.findInputFocusContextKey, webViewOptions);
const removeLayoutParticipant = arrays.insert(this.layoutParticipants, this.activeWebview);
this.contentDisposables.push(toDisposable(removeLayoutParticipant));
this.activeWebview.contents = body;
Expand Down
1 change: 1 addition & 0 deletions src/vs/workbench/parts/html/browser/html.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ function getActivePreviewsForResource(accessor: ServicesAccessor, resource: URI
}

// --- Register Editor

(<IEditorRegistry>Registry.as(EditorExtensions.Editors)).registerEditor(new EditorDescriptor(
HtmlPreviewPart,
HtmlPreviewPart.ID,
Expand Down
5 changes: 1 addition & 4 deletions src/vs/workbench/parts/html/browser/htmlPreviewPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import { Webview, WebviewOptions } from './webview';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { WebviewEditor } from './webviewEditor';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';


/**
Expand Down Expand Up @@ -55,8 +54,7 @@ export class HtmlPreviewPart extends WebviewEditor {
@IOpenerService private readonly openerService: IOpenerService,
@IPartService private readonly partService: IPartService,
@IContextViewService private readonly _contextViewService: IContextViewService,
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService
@IEnvironmentService private readonly _environmentService: IEnvironmentService
) {
super(HtmlPreviewPart.ID, telemetryService, themeService, storageService, contextKeyService);
}
Expand Down Expand Up @@ -93,7 +91,6 @@ export class HtmlPreviewPart extends WebviewEditor {
this.partService.getContainer(Parts.EDITOR_PART),
this.themeService,
this._environmentService,
this._contextService,
this._contextViewService,
this.contextKey,
this.findInputFocusContextKey,
Expand Down
16 changes: 7 additions & 9 deletions src/vs/workbench/parts/html/browser/webview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { normalize, nativeSep } from 'vs/base/common/paths';
import { startsWith } from 'vs/base/common/strings';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';

export interface WebviewOptions {
readonly allowScripts?: boolean;
readonly allowSvgs?: boolean;
readonly svgWhiteList?: string[];
readonly enableWrappedPostMessage?: boolean;
readonly useSameOriginForRoot?: boolean;
readonly localResourceRoots?: URI[];
}

export class Webview {
Expand All @@ -41,7 +41,6 @@ export class Webview {
private readonly _styleElement: Element,
private readonly _themeService: IThemeService,
private readonly _environmentService: IEnvironmentService,
private readonly _contextService: IWorkspaceContextService,
private readonly _contextViewService: IContextViewService,
private readonly _contextKey: IContextKey<boolean>,
private readonly _findInputContextKey: IContextKey<boolean>,
Expand Down Expand Up @@ -321,16 +320,16 @@ export class Webview {
return;
}

registerFileProtocol(contents, 'vscode-core-resource', [
registerFileProtocol(contents, 'vscode-core-resource', () => [
this._environmentService.appRoot
]);
registerFileProtocol(contents, 'vscode-extension-resource', [
registerFileProtocol(contents, 'vscode-extension-resource', () => [
this._environmentService.extensionsPath,
this._environmentService.appRoot,
this._environmentService.extensionDevelopmentPath
]);
registerFileProtocol(contents, 'vscode-workspace-resource',
this._contextService.getWorkspace().folders.map(folder => folder.uri.fsPath)
registerFileProtocol(contents, 'vscode-workspace-resource', () =>
this._options.localResourceRoots.map(uri => uri.fsPath)
);
}

Expand All @@ -352,7 +351,6 @@ export class Webview {

this._findStarted = true;
this._webview.findInPage(value, findOptions);
return;
}

/**
Expand Down Expand Up @@ -425,11 +423,11 @@ namespace ApiThemeClassName {
function registerFileProtocol(
contents: Electron.WebContents,
protocol: string,
roots: string[]
getRoots: () => string[]
) {
contents.session.protocol.registerFileProtocol(protocol, (request, callback: any) => {
const requestPath = URI.parse(request.url).fsPath;
for (const root of roots) {
for (const root of getRoots()) {
const normalizedPath = normalize(requestPath, true);
if (startsWith(normalizedPath, root + nativeSep)) {
callback({ path: normalizedPath });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { onUnexpectedError } from 'vs/base/common/errors';
import { addGAParameters } from 'vs/platform/telemetry/node/telemetryNodeUtils';
import { generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/tokenization';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';

function renderBody(
body: string,
Expand Down Expand Up @@ -64,8 +63,7 @@ export class ReleaseNotesEditor extends WebviewEditor {
@IOpenerService private readonly openerService: IOpenerService,
@IModeService private readonly modeService: IModeService,
@IPartService private readonly partService: IPartService,
@IContextViewService private readonly _contextViewService: IContextViewService,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService
@IContextViewService private readonly _contextViewService: IContextViewService
) {
super(ReleaseNotesEditor.ID, telemetryService, themeService, storageService, contextKeyService);
}
Expand Down Expand Up @@ -93,7 +91,6 @@ export class ReleaseNotesEditor extends WebviewEditor {
this.partService.getContainer(Parts.EDITOR_PART),
this.themeService,
this.environmentService,
this._contextService,
this._contextViewService,
this.contextKey,
this.findInputFocusContextKey,
Expand Down

0 comments on commit 2d1f6d4

Please sign in to comment.