From f9e50b8ac19711ab4c1a6e7c3f2e8cc20657d5e8 Mon Sep 17 00:00:00 2001 From: Guillaume Fontorbe Date: Mon, 4 Dec 2023 18:05:50 +0100 Subject: [PATCH] Add meta content security policy to generated html (#98) Signed-off-by: Guillaume Fontorbe --- examples/states-webview/webpack.config.js | 2 +- .../src/sprotty-editor-provider.ts | 16 ++++--- .../src/sprotty-view-provider.ts | 16 ++++--- .../src/webview-panel-manager.ts | 43 +++++++++++++------ packages/sprotty-vscode/src/webview-utils.ts | 8 ++-- 5 files changed, 59 insertions(+), 26 deletions(-) diff --git a/examples/states-webview/webpack.config.js b/examples/states-webview/webpack.config.js index 6c6f624..a240c5a 100644 --- a/examples/states-webview/webpack.config.js +++ b/examples/states-webview/webpack.config.js @@ -12,7 +12,7 @@ const config = { filename: 'webview.js', path: outputPath }, - devtool: 'eval-source-map', + devtool: 'source-map', resolve: { extensions: ['.ts', '.tsx', '.js'] diff --git a/packages/sprotty-vscode/src/sprotty-editor-provider.ts b/packages/sprotty-vscode/src/sprotty-editor-provider.ts index 5c01def..6492cee 100644 --- a/packages/sprotty-vscode/src/sprotty-editor-provider.ts +++ b/packages/sprotty-vscode/src/sprotty-editor-provider.ts @@ -17,14 +17,16 @@ import { SprottyDiagramIdentifier } from 'sprotty-vscode-protocol'; import * as vscode from 'vscode'; import { Messenger } from 'vscode-messenger'; -import { isWebviewPanel, IWebviewEndpointManager, OpenDiagramOptions, WebviewEndpoint } from './webview-endpoint'; +import { isWebviewPanel, IWebviewEndpointManager, OpenDiagramOptions, WebviewContainer, WebviewEndpoint } from './webview-endpoint'; import { createFileUri, createWebviewHtml, getExtname, serializeUri } from './webview-utils'; export interface SprottyEditorProviderOptions { extensionUri: vscode.Uri viewType: string messenger?: Messenger - supportedFileExtensions?: string[]; + supportedFileExtensions?: string[] + createWebviewHtml?: (identifier: SprottyDiagramIdentifier, container: WebviewContainer) => string + localResourceRoots?: vscode.Uri[] } export type CustomDocumentChangeEvent = vscode.CustomDocumentEditEvent | vscode.CustomDocumentContentChangeEvent; @@ -116,13 +118,17 @@ export class SprottyEditorProvider implements vscode.CustomEditorProvider, IWebv protected configureWebview(document: SprottyDocument, webviewPanel: vscode.WebviewPanel, cancelToken: vscode.CancellationToken): Promise | void { const extensionPath = this.options.extensionUri.fsPath; webviewPanel.webview.options = { - localResourceRoots: [ createFileUri(extensionPath, 'pack') ], + localResourceRoots: this.options.localResourceRoots ?? [ createFileUri(extensionPath, 'pack') ], enableScripts: true }; const identifier = document.endpoint?.diagramIdentifier; if (identifier) { - const scriptUri = createFileUri(extensionPath, 'pack', 'webview.js'); - webviewPanel.webview.html = createWebviewHtml(identifier, webviewPanel, { scriptUri }); + if (this.options.createWebviewHtml) { + webviewPanel.webview.html = this.options.createWebviewHtml(identifier, webviewPanel); + } else { + const scriptUri = createFileUri(extensionPath, 'pack', 'webview.js'); + webviewPanel.webview.html = createWebviewHtml(identifier, webviewPanel, { scriptUri }); + } } } diff --git a/packages/sprotty-vscode/src/sprotty-view-provider.ts b/packages/sprotty-vscode/src/sprotty-view-provider.ts index 4b71bbb..fe1aafd 100644 --- a/packages/sprotty-vscode/src/sprotty-view-provider.ts +++ b/packages/sprotty-vscode/src/sprotty-view-provider.ts @@ -17,15 +17,17 @@ import { SprottyDiagramIdentifier } from 'sprotty-vscode-protocol'; import * as vscode from 'vscode'; import { Messenger } from 'vscode-messenger'; -import { isWebviewView, IWebviewEndpointManager, OpenDiagramOptions, WebviewEndpoint } from './webview-endpoint'; +import { isWebviewView, IWebviewEndpointManager, OpenDiagramOptions, WebviewContainer, WebviewEndpoint } from './webview-endpoint'; import { createFileUri, createWebviewHtml, getExtname, serializeUri } from './webview-utils'; export interface SprottyViewProviderOptions { extensionUri: vscode.Uri viewType: string messenger?: Messenger - supportedFileExtensions?: string[]; + supportedFileExtensions?: string[] openActiveEditor?: boolean + createWebviewHtml?: (identifier: SprottyDiagramIdentifier, container: WebviewContainer) => string + localResourceRoots?: vscode.Uri[] } export interface OpenViewOptions extends OpenDiagramOptions { @@ -113,7 +115,7 @@ export class SprottyViewProvider implements vscode.WebviewViewProvider, IWebview protected configureWebview(webviewView: vscode.WebviewView, endpoint: WebviewEndpoint, cancelToken: vscode.CancellationToken): Promise | void { const extensionPath = this.options.extensionUri.fsPath; webviewView.webview.options = { - localResourceRoots: [ createFileUri(extensionPath, 'pack') ], + localResourceRoots: this.options.localResourceRoots ?? [ createFileUri(extensionPath, 'pack') ], enableScripts: true }; let identifier = endpoint.diagramIdentifier; @@ -121,8 +123,12 @@ export class SprottyViewProvider implements vscode.WebviewViewProvider, IWebview // Create a preliminary diagram identifier to fill the webview's HTML content identifier = { clientId: this.clientId, diagramType: this.options.viewType, uri: '' }; } - const scriptUri = createFileUri(extensionPath, 'pack', 'webview.js'); - webviewView.webview.html = createWebviewHtml(identifier, webviewView, { scriptUri }); + if (this.options.createWebviewHtml) { + webviewView.webview.html = this.options.createWebviewHtml(identifier, webviewView); + } else { + const scriptUri = createFileUri(extensionPath, 'pack', 'webview.js'); + webviewView.webview.html = createWebviewHtml(identifier, webviewView, { scriptUri }); + } } protected async createDiagramIdentifier(uri: vscode.Uri, diagramType?: string): Promise { diff --git a/packages/sprotty-vscode/src/webview-panel-manager.ts b/packages/sprotty-vscode/src/webview-panel-manager.ts index 9749d7f..eb88043 100644 --- a/packages/sprotty-vscode/src/webview-panel-manager.ts +++ b/packages/sprotty-vscode/src/webview-panel-manager.ts @@ -17,19 +17,21 @@ import { SprottyDiagramIdentifier } from 'sprotty-vscode-protocol'; import * as vscode from 'vscode'; import { Messenger } from 'vscode-messenger'; -import { isWebviewPanel, IWebviewEndpointManager, OpenDiagramOptions, WebviewEndpoint } from './webview-endpoint'; -import { createFileUri, createWebviewPanel, createWebviewTitle, getExtname, serializeUri } from './webview-utils'; +import { isWebviewPanel, IWebviewEndpointManager, OpenDiagramOptions, WebviewContainer, WebviewEndpoint } from './webview-endpoint'; +import { createFileUri, createWebviewHtml, createWebviewTitle, getExtname, serializeUri } from './webview-utils'; export interface WebviewPanelManagerOptions { - extensionUri: vscode.Uri - messenger?: Messenger - defaultDiagramType?: string - supportedFileExtensions?: string[] - singleton?: boolean + extensionUri: vscode.Uri; + messenger?: Messenger; + defaultDiagramType?: string; + supportedFileExtensions?: string[]; + singleton?: boolean; + createWebviewHtml?: (identifier: SprottyDiagramIdentifier, container: WebviewContainer) => string; + localResourceRoots?: vscode.Uri[]; } export interface OpenPanelOptions extends OpenDiagramOptions { - preserveFocus?: boolean + preserveFocus?: boolean; } /** @@ -106,10 +108,27 @@ export class WebviewPanelManager implements IWebviewEndpointManager { */ protected createWebview(identifier: SprottyDiagramIdentifier): vscode.WebviewPanel { const extensionPath = this.options.extensionUri.fsPath; - return createWebviewPanel(identifier, { - localResourceRoots: [ createFileUri(extensionPath, 'pack') ], - scriptUri: createFileUri(extensionPath, 'pack', 'webview.js') - }); + + const title = createWebviewTitle(identifier); + const diagramPanel = vscode.window.createWebviewPanel( + identifier.diagramType || 'diagram', + title, + vscode.ViewColumn.Beside, + { + localResourceRoots: this.options.localResourceRoots ?? [createFileUri(extensionPath, 'pack')], + enableScripts: true, + retainContextWhenHidden: true + } + ); + + if (this.options.createWebviewHtml) { + diagramPanel.webview.html = this.options.createWebviewHtml(identifier, diagramPanel); + } else { + const scriptUri = createFileUri(extensionPath, 'pack', 'webview.js'); + diagramPanel.webview.html = createWebviewHtml(identifier, diagramPanel, { scriptUri }); + } + + return diagramPanel; } protected async createDiagramIdentifier(uri: vscode.Uri, diagramType?: string): Promise { diff --git a/packages/sprotty-vscode/src/webview-utils.ts b/packages/sprotty-vscode/src/webview-utils.ts index baff412..1883f8f 100644 --- a/packages/sprotty-vscode/src/webview-utils.ts +++ b/packages/sprotty-vscode/src/webview-utils.ts @@ -28,8 +28,9 @@ export function serializeUri(uri: vscode.Uri): string { return uriString; } +/** @deprecated */ export function createWebviewPanel(identifier: SprottyDiagramIdentifier, - options: { localResourceRoots: vscode.Uri[], scriptUri: vscode.Uri, cssUri?: vscode.Uri }): vscode.WebviewPanel { + options: { localResourceRoots: vscode.Uri[], scriptUri: vscode.Uri, cssUri?: vscode.Uri; }): vscode.WebviewPanel { const title = createWebviewTitle(identifier); const diagramPanel = vscode.window.createWebviewPanel( identifier.diagramType || 'diagram', @@ -43,7 +44,7 @@ export function createWebviewPanel(identifier: SprottyDiagramIdentifier, diagramPanel.webview.html = createWebviewHtml(identifier, diagramPanel, { scriptUri: options.scriptUri, cssUri: options.cssUri, - title + title, }); return diagramPanel; } @@ -60,7 +61,7 @@ export function createWebviewTitle(identifier: SprottyDiagramIdentifier): string } export function createWebviewHtml(identifier: SprottyDiagramIdentifier, container: WebviewContainer, - options: { scriptUri: vscode.Uri, cssUri?: vscode.Uri, title?: string }): string { + options: { scriptUri: vscode.Uri, cssUri?: vscode.Uri, title?: string; }): string { const transformUri = (uri: vscode.Uri) => container.webview.asWebviewUri(uri).toString(); return ` @@ -69,6 +70,7 @@ export function createWebviewHtml(identifier: SprottyDiagramIdentifier, containe ${options.title ? `${options.title}` : ''} ${options.cssUri ? `` : ''} +