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

Add meta content security policy to generated html #98

Merged
merged 4 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/states-webview/webpack.config.js
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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