Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/microsoft/vscode.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Bierner <matb@microsoft.com>2021-08-19 02:34:31 +0300
committerGitHub <noreply@github.com>2021-08-19 02:34:31 +0300
commit3866c3553be8b268c8a7f8c0482c0c0177aa8bfa (patch)
treeb06ce638514cd8c507616e17981ef1d87400632a
parentdb376868f4343e02b6d2d9e3d223d4c68d23813e (diff)
Use insane with notebook markdown content (#131134)1.59.1release/1.59
Runs insane against markdown content. Also requires hooking up a way for renderers to detect if the workspace is trusted or not
-rw-r--r--extensions/markdown-language-features/notebook/index.ts48
-rw-r--r--extensions/markdown-language-features/notebook/insane.d.ts19
-rw-r--r--extensions/markdown-language-features/package.json1
-rw-r--r--extensions/markdown-language-features/yarn.lock18
-rw-r--r--src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts17
-rw-r--r--src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts8
-rw-r--r--src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts56
7 files changed, 150 insertions, 17 deletions
diff --git a/extensions/markdown-language-features/notebook/index.ts b/extensions/markdown-language-features/notebook/index.ts
index 699bd2129ad..81eae896395 100644
--- a/extensions/markdown-language-features/notebook/index.ts
+++ b/extensions/markdown-language-features/notebook/index.ts
@@ -4,8 +4,48 @@
*--------------------------------------------------------------------------------------------*/
const MarkdownIt = require('markdown-it');
+const insane = require('insane');
+import type { InsaneOptions } from 'insane';
+
+function _extInsaneOptions(opts: InsaneOptions, allowedAttributesForAll: string[]): InsaneOptions {
+ const allowedAttributes: Record<string, string[]> = opts.allowedAttributes ?? {};
+ if (opts.allowedTags) {
+ for (const tag of opts.allowedTags) {
+ let array = allowedAttributes[tag];
+ if (!array) {
+ array = allowedAttributesForAll;
+ } else {
+ array = array.concat(allowedAttributesForAll);
+ }
+ allowedAttributes[tag] = array;
+ }
+ }
+
+ return { ...opts, allowedAttributes };
+}
-export function activate() {
+const insaneOptions: InsaneOptions = _extInsaneOptions({
+ allowedTags: ['a', 'button', 'blockquote', 'code', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'img', 'input', 'label', 'li', 'p', 'pre', 'select', 'small', 'span', 'strong', 'textarea', 'ul', 'ol'],
+ allowedAttributes: {
+ 'a': ['href', 'x-dispatch'],
+ 'button': ['data-href', 'x-dispatch'],
+ 'img': ['src'],
+ 'input': ['type', 'placeholder', 'checked', 'required'],
+ 'label': ['for'],
+ 'select': ['required'],
+ 'span': ['data-command', 'role'],
+ 'textarea': ['name', 'placeholder', 'required'],
+ },
+ allowedSchemes: ['http', 'https']
+}, [
+ 'align',
+ 'class',
+ 'id',
+ 'style',
+ 'aria-hidden',
+]);
+
+export function activate(ctx: { workspace: { isTrusted: boolean } }) {
let markdownIt = new MarkdownIt({
html: true
});
@@ -172,8 +212,10 @@ export function activate() {
} else {
previewNode.classList.remove('emptyMarkdownCell');
- const rendered = markdownIt.render(text);
- previewNode.innerHTML = rendered;
+ const unsanitizedRenderedMarkdown = markdownIt.render(text);
+ previewNode.innerHTML = ctx.workspace.isTrusted
+ ? unsanitizedRenderedMarkdown
+ : insane(unsanitizedRenderedMarkdown, insaneOptions);
}
},
extendMarkdownIt: (f: (md: typeof markdownIt) => void) => {
diff --git a/extensions/markdown-language-features/notebook/insane.d.ts b/extensions/markdown-language-features/notebook/insane.d.ts
new file mode 100644
index 00000000000..84db6f6ecff
--- /dev/null
+++ b/extensions/markdown-language-features/notebook/insane.d.ts
@@ -0,0 +1,19 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+declare module 'insane' {
+ export interface InsaneOptions {
+ readonly allowedSchemes?: readonly string[],
+ readonly allowedTags?: readonly string[],
+ readonly allowedAttributes?: { readonly [key: string]: string[] },
+ readonly filter?: (token: { tag: string, attrs: { readonly [key: string]: string } }) => boolean,
+ }
+
+ export function insane(
+ html: string,
+ options?: InsaneOptions,
+ strict?: boolean,
+ ): string;
+}
diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json
index f9750857b35..969f6edf80f 100644
--- a/extensions/markdown-language-features/package.json
+++ b/extensions/markdown-language-features/package.json
@@ -353,6 +353,7 @@
},
"dependencies": {
"highlight.js": "^10.4.1",
+ "insane": "^2.6.2",
"markdown-it": "^12.0.3",
"markdown-it-front-matter": "^0.2.1",
"vscode-extension-telemetry": "0.2.6",
diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock
index 1ecfce6a73b..2d35c914c61 100644
--- a/extensions/markdown-language-features/yarn.lock
+++ b/extensions/markdown-language-features/yarn.lock
@@ -36,16 +36,34 @@ argparse@^2.0.1:
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+assignment@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/assignment/-/assignment-2.0.0.tgz#ffd17b21bf5d6b22e777b989681a815456a3dd3e"
+ integrity sha1-/9F7Ib9dayLnd7mJaBqBVFaj3T4=
+
entities@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5"
integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==
+he@0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/he/-/he-0.5.0.tgz#2c05ffaef90b68e860f3fd2b54ef580989277ee2"
+ integrity sha1-LAX/rvkLaOhg8/0rVO9YCYknfuI=
+
highlight.js@*, highlight.js@^10.4.1:
version "10.4.1"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.4.1.tgz#d48fbcf4a9971c4361b3f95f302747afe19dbad0"
integrity sha512-yR5lWvNz7c85OhVAEAeFhVCc/GV4C30Fjzc/rCP0aCWzc1UUOPUk55dK/qdwTZHBvMZo+eZ2jpk62ndX/xMFlg==
+insane@^2.6.2:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/insane/-/insane-2.6.2.tgz#c2ab68bb3e006ab451560d1b446917329c0a8120"
+ integrity sha1-wqtouz4AarRRVg0bRGkXMpwKgSA=
+ dependencies:
+ assignment "2.0.0"
+ he "0.5.0"
+
linkify-it@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.2.tgz#f55eeb8bc1d3ae754049e124ab3bb56d97797fb8"
diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts
index 58539657764..0ae0871b060 100644
--- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts
+++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts
@@ -24,6 +24,7 @@ import { IFileService } from 'vs/platform/files/common/files';
import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
+import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
import { asWebviewUri } from 'vs/workbench/api/common/shared/webview';
import { CellEditState, ICellOutputViewModel, ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { preloadsScriptStr, RendererMetadata } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads';
@@ -102,6 +103,7 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
@IMenuService private readonly menuService: IMenuService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
+ @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService,
) {
super();
@@ -127,6 +129,13 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
return Promise.resolve(true);
};
}
+
+ this._register(workspaceTrustManagementService.onDidChangeTrust(e => {
+ this._sendMessageToWebview({
+ type: 'updateWorkspaceTrust',
+ isTrusted: e,
+ });
+ }));
}
updateOptions(options: {
@@ -182,6 +191,12 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
private generateContent(baseUrl: string) {
const renderersData = this.getRendererData();
+ const preloadScript = preloadsScriptStr(
+ this.options,
+ { dragAndDropEnabled: this.options.dragAndDropEnabled },
+ renderersData,
+ this.workspaceTrustManagementService.isWorkspaceTrusted());
+
return html`
<html lang="en">
<head>
@@ -302,7 +317,7 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
</head>
<body style="overflow: hidden;">
<div id='container' class="widgetarea" style="position: absolute;width:100%;top: 0px"></div>
- <script type="module">${preloadsScriptStr(this.options, { dragAndDropEnabled: this.options.dragAndDropEnabled }, renderersData)}</script>
+ <script type="module">${preloadScript}</script>
</body>
</html>`;
}
diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts
index ba9f9488d70..a5f070af6b0 100644
--- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts
+++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts
@@ -326,6 +326,11 @@ export interface INotebookOptionsMessage {
readonly options: PreloadOptions;
}
+export interface INotebookUpdateWorkspaceTrust {
+ readonly type: 'updateWorkspaceTrust';
+ readonly isTrusted: boolean;
+}
+
export type FromWebviewMessage = WebviewIntialized |
IDimensionMessage |
IMouseEnterMessage |
@@ -373,6 +378,7 @@ export type ToWebviewMessage = IClearMessage |
IUpdateSelectedMarkupCellsMessage |
IInitializeMarkupCells |
INotebookStylesMessage |
- INotebookOptionsMessage;
+ INotebookOptionsMessage |
+ INotebookUpdateWorkspaceTrust;
export type AnyMessage = FromWebviewMessage | ToWebviewMessage;
diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts
index a3b61d41688..4b102e17624 100644
--- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts
+++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts
@@ -43,10 +43,18 @@ export interface PreloadOptions {
dragAndDropEnabled: boolean;
}
+interface PreloadContext {
+ readonly style: PreloadStyles;
+ readonly options: PreloadOptions;
+ readonly rendererData: readonly RendererMetadata[];
+ readonly isWorkspaceTrusted: boolean;
+}
+
declare function __import(path: string): Promise<any>;
-async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, rendererData: readonly RendererMetadata[]) {
- let currentOptions = options;
+async function webviewPreloads(ctx: PreloadContext) {
+ let currentOptions = ctx.options;
+ let isWorkspaceTrusted = ctx.isWorkspaceTrusted;
const acquireVsCodeApi = globalThis.acquireVsCodeApi;
const vscode = acquireVsCodeApi();
@@ -133,6 +141,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
getRenderer(id: string): Promise<any | undefined>;
postMessage?(message: unknown): void;
onDidReceiveMessage?: Event<unknown>;
+ readonly workspace: { readonly isTrusted: boolean };
}
interface ScriptModule {
@@ -207,7 +216,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
if (entry.target.id === observedElementInfo.id && entry.contentRect) {
if (observedElementInfo.output) {
if (entry.contentRect.height !== 0) {
- entry.target.style.padding = `${style.outputNodePadding}px 0 ${style.outputNodePadding}px 0`;
+ entry.target.style.padding = `${ctx.style.outputNodePadding}px 0 ${ctx.style.outputNodePadding}px 0`;
} else {
entry.target.style.padding = `0px`;
}
@@ -549,12 +558,12 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
if (offsetHeight !== 0 && cps.padding === '0px') {
// we set padding to zero if the output height is zero (then we can have a zero-height output DOM node)
// thus we need to ensure the padding is accounted when updating the init height of the output
- dimensionUpdater.updateHeight(outputId, offsetHeight + style.outputNodePadding * 2, {
+ dimensionUpdater.updateHeight(outputId, offsetHeight + ctx.style.outputNodePadding * 2, {
isOutput: true,
init: true,
});
- outputNode.style.padding = `${style.outputNodePadding}px 0 ${style.outputNodePadding}px 0`;
+ outputNode.style.padding = `${ctx.style.outputNodePadding}px 0 ${ctx.style.outputNodePadding}px 0`;
} else {
dimensionUpdater.updateHeight(outputId, outputNode.offsetHeight, {
isOutput: true,
@@ -657,6 +666,12 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
currentOptions = event.data.options;
viewModel.toggleDragDropEnabled(currentOptions.dragAndDropEnabled);
break;
+
+ case 'updateWorkspaceTrust': {
+ isWorkspaceTrusted = event.data.isTrusted;
+ viewModel.rerenderMarkupCells();
+ break;
+ }
}
});
@@ -700,6 +715,9 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
// TODO: This is async so that we can return a promise to the API in the future.
// Currently the API is always resolved before we call `createRendererContext`.
getRenderer: async (id: string) => renderers.getRenderer(id)?.api,
+ workspace: {
+ get isTrusted() { return isWorkspaceTrusted; }
+ }
};
if (messaging) {
@@ -722,7 +740,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
// Squash any errors extends errors. They won't prevent the renderer
// itself from working, so just log them.
- await Promise.all(rendererData
+ await Promise.all(ctx.rendererData
.filter(d => d.extends === this.data.id)
.map(d => this.loadExtension(d.id).catch(console.error)),
);
@@ -807,7 +825,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
private readonly _renderers = new Map</* id */ string, Renderer>();
constructor() {
- for (const renderer of rendererData) {
+ for (const renderer of ctx.rendererData) {
this._renderers.set(renderer.id, new Renderer(renderer, async (extensionId) => {
const ext = this._renderers.get(extensionId);
if (!ext) {
@@ -936,6 +954,12 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
cell?.unhide();
}
+ public rerenderMarkupCells() {
+ for (const cell of this._markupCells.values()) {
+ cell.rerender();
+ }
+ }
+
private getExpectedMarkupCell(id: string): MarkupCell | undefined {
const cell = this._markupCells.get(id);
if (!cell) {
@@ -1166,6 +1190,10 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
}
}
+ public rerender() {
+ this.updateContentAndRender(this._content);
+ }
+
public hide() {
this.element.style.visibility = 'hidden';
}
@@ -1409,14 +1437,18 @@ export interface RendererMetadata {
readonly messaging: boolean;
}
-export function preloadsScriptStr(styleValues: PreloadStyles, options: PreloadOptions, renderers: readonly RendererMetadata[]) {
- // TS will try compiling `import()` in webviePreloads, so use an helper function instead
+export function preloadsScriptStr(styleValues: PreloadStyles, options: PreloadOptions, renderers: readonly RendererMetadata[], isWorkspaceTrusted: boolean) {
+ const ctx: PreloadContext = {
+ style: styleValues,
+ options,
+ rendererData: renderers,
+ isWorkspaceTrusted
+ };
+ // TS will try compiling `import()` in webviewPreloads, so use an helper function instead
// of using `import(...)` directly
return `
const __import = (x) => import(x);
(${webviewPreloads})(
- JSON.parse(decodeURIComponent("${encodeURIComponent(JSON.stringify(styleValues))}")),
- JSON.parse(decodeURIComponent("${encodeURIComponent(JSON.stringify(options))}")),
- JSON.parse(decodeURIComponent("${encodeURIComponent(JSON.stringify(renderers))}"))
+ JSON.parse(decodeURIComponent("${encodeURIComponent(JSON.stringify(ctx))}"))
)\n//# sourceURL=notebookWebviewPreloads.js\n`;
}