Skip to content

Commit

Permalink
Add meta content security policy to generated html (#98)
Browse files Browse the repository at this point in the history
Signed-off-by: Guillaume Fontorbe <guillaume.fontorbe@typefox.io>
  • Loading branch information
gfontorbe committed Dec 4, 2023
1 parent 24764a8 commit f9e50b8
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 26 deletions.
2 changes: 1 addition & 1 deletion examples/states-webview/webpack.config.js
Expand Up @@ -12,7 +12,7 @@ const config = {
filename: 'webview.js',
path: outputPath
},
devtool: 'eval-source-map',
devtool: 'source-map',

resolve: {
extensions: ['.ts', '.tsx', '.js']
Expand Down
16 changes: 11 additions & 5 deletions packages/sprotty-vscode/src/sprotty-editor-provider.ts
Expand Up @@ -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.CustomDocument> | vscode.CustomDocumentContentChangeEvent<vscode.CustomDocument>;
Expand Down Expand Up @@ -116,13 +118,17 @@ export class SprottyEditorProvider implements vscode.CustomEditorProvider, IWebv
protected configureWebview(document: SprottyDocument, webviewPanel: vscode.WebviewPanel, cancelToken: vscode.CancellationToken): Promise<void> | 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 });
}
}
}

Expand Down
16 changes: 11 additions & 5 deletions packages/sprotty-vscode/src/sprotty-view-provider.ts
Expand Up @@ -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 {
Expand Down Expand Up @@ -113,16 +115,20 @@ export class SprottyViewProvider implements vscode.WebviewViewProvider, IWebview
protected configureWebview(webviewView: vscode.WebviewView, endpoint: WebviewEndpoint, cancelToken: vscode.CancellationToken): Promise<void> | 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;
if (!identifier) {
// 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<SprottyDiagramIdentifier | undefined> {
Expand Down
43 changes: 31 additions & 12 deletions packages/sprotty-vscode/src/webview-panel-manager.ts
Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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<SprottyDiagramIdentifier | undefined> {
Expand Down
8 changes: 5 additions & 3 deletions packages/sprotty-vscode/src/webview-utils.ts
Expand Up @@ -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',
Expand All @@ -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;
}
Expand All @@ -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 `<!DOCTYPE html>
<html lang="en">
Expand All @@ -69,6 +70,7 @@ export function createWebviewHtml(identifier: SprottyDiagramIdentifier, containe
<meta name="viewport" content="width=device-width, height=device-height">
${options.title ? `<title>${options.title}</title>` : ''}
${options.cssUri ? `<link rel="stylesheet" type="text/css" href="${transformUri(options.cssUri)}" />` : ''}
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src ${container.webview.cspSource}; style-src 'unsafe-inline' ${container.webview.cspSource};">
</head>
<body>
<div id="${identifier.clientId}_container" style="height: 100%;"></div>
Expand Down

0 comments on commit f9e50b8

Please sign in to comment.