Fix markdown security and enable most CSS (#5263)

* Fix markdown security and enable most CSS

Stops using our sanitizer and instead disables HTML in markdown engine
- This was blocking Note because it converted > to >
- It's slightly more strict in that it fully disables HTML unless trusted. Will need to improve handling of Trusted to support this in a future PR

Adds in correct CSS, both from .css file in markdown extension and from built-into all webviews global CSS
- Fix #3765 standard markdown support
- Fix Support of Notes by bringing correct styles
- Fix code block colorization
- Fix link handling so it's not bolded / gets underlined on hover
- Fixes table rendering (for markdown and HTML tables)

* Reduce scope of CSS changes
- Removed some CSS that wasn't needed or caused issues
- Scoped most things under the preview section not the whole component

* Avoid markdown html block by sanitizing after render

* Fix pre node not overflowing
- This was a bug in existing implementation too
This commit is contained in:
Kevin Cunnane
2019-04-30 14:21:20 -07:00
committed by GitHub
parent e72d0d03ed
commit b21125ff2d
5 changed files with 462 additions and 7 deletions

View File

@@ -0,0 +1,182 @@
/*
https://raw.githubusercontent.com/isagalaev/highlight.js/master/src/styles/vs2015.css
*/
/*
* Visual Studio 2015 dark style
* Author: Nicolas LLOBERA <nllobera@gmail.com>
*/
.notebook-preview .hljs-keyword,
.notebook-preview .hljs-literal,
.notebook-preview .hljs-symbol,
.notebook-preview .hljs-name {
color: #569CD6;
}
.notebook-preview .hljs-link {
color: #569CD6;
text-decoration: underline;
}
.notebook-preview .hljs-built_in,
.notebook-preview .hljs-type {
color: #4EC9B0;
}
.notebook-preview .hljs-number,
.notebook-preview .hljs-class {
color: #B8D7A3;
}
.notebook-preview .hljs-string,
.notebook-preview .hljs-meta-string {
color: #D69D85;
}
.notebook-preview .hljs-regexp,
.notebook-preview .hljs-template-tag {
color: #9A5334;
}
.notebook-preview .hljs-subst,
.notebook-preview .hljs-function,
.notebook-preview .hljs-title,
.notebook-preview .hljs-params,
.notebook-preview .hljs-formula {
color: #DCDCDC;
}
.notebook-preview .hljs-comment,
.notebook-preview .hljs-quote {
color: #57A64A;
font-style: italic;
}
.notebook-preview .hljs-doctag {
color: #608B4E;
}
.notebook-preview .hljs-meta,
.notebook-preview .hljs-meta-keyword,
.notebook-preview .hljs-tag {
color: #9B9B9B;
}
.notebook-preview .hljs-variable,
.notebook-preview .hljs-template-variable {
color: #BD63C5;
}
.notebook-preview .hljs-attr,
.notebook-preview .hljs-attribute,
.notebook-preview .hljs-builtin-name {
color: #9CDCFE;
}
.notebook-preview .hljs-section {
color: gold;
}
.notebook-preview .hljs-emphasis {
font-style: italic;
}
.notebook-preview .hljs-strong {
font-weight: bold;
}
/*.hljs-code {
font-family:'Monospace';
}*/
.notebook-preview .hljs-bullet,
.notebook-preview .hljs-selector-tag,
.notebook-preview .hljs-selector-id,
.notebook-preview .hljs-selector-class,
.notebook-preview .hljs-selector-attr,
.notebook-preview .hljs-selector-pseudo {
color: #D7BA7D;
}
.notebook-preview .hljs-addition {
background-color: var(--vscode-diffEditor-insertedTextBackground, rgba(155, 185, 85, 0.2));
color: rgb(155, 185, 85);
display: inline-block;
width: 100%;
}
.notebook-preview .hljs-deletion {
background: var(--vscode-diffEditor-removedTextBackground, rgba(255, 0, 0, 0.2));
color: rgb(255, 0, 0);
display: inline-block;
width: 100%;
}
/*
From https://raw.githubusercontent.com/isagalaev/highlight.js/master/src/styles/vs.css
*/
/*
Visual Studio-like style based on original C# coloring by Jason Diamond <jason@diamond.name>
*/
.notebook-preview .hljs-function,
.notebook-preview .hljs-params {
color: inherit;
}
.notebook-preview .hljs-comment,
.notebook-preview .hljs-quote,
.notebook-preview .hljs-variable {
color: #008000;
}
.notebook-preview .hljs-keyword,
.notebook-preview .hljs-selector-tag,
.notebook-preview .hljs-built_in,
.notebook-preview .hljs-name,
.notebook-preview .hljs-tag {
color: #00f;
}
.notebook-preview .hljs-string,
.notebook-preview .hljs-title,
.notebook-preview .hljs-section,
.notebook-preview .hljs-attribute,
.notebook-preview .hljs-literal,
.notebook-preview .hljs-template-tag,
.notebook-preview .hljs-template-variable,
.notebook-preview .hljs-type {
color: #a31515;
}
.notebook-preview .hljs-selector-attr,
.notebook-preview .hljs-selector-pseudo,
.notebook-preview .hljs-meta {
color: #2b91af;
}
.notebook-preview .hljs-doctag {
color: #808080;
}
.notebook-preview .hljs-attr {
color: #f00;
}
.notebook-preview .hljs-symbol,
.notebook-preview .hljs-bullet,
.notebook-preview .hljs-link {
color: #00b0e8;
}
.notebook-preview .hljs-emphasis {
font-style: italic;
}
.notebook-preview .hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,231 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.notebook-preview {
font-size: 14px;
line-height: 22px;
word-wrap: break-word;
}
.notebook-preview #code-csp-warning {
position: fixed;
top: 0;
right: 0;
color: white;
margin: 16px;
text-align: center;
font-size: 12px;
font-family: sans-serif;
background-color:#444444;
cursor: pointer;
padding: 6px;
box-shadow: 1px 1px 1px rgba(0,0,0,.25);
}
.notebook-preview #code-csp-warning:hover {
text-decoration: none;
background-color:#007acc;
box-shadow: 2px 2px 2px rgba(0,0,0,.25);
}
.notebook-preview .scrollBeyondLastLine {
margin-bottom: calc(100vh - 22px);
}
.notebook-preview .showEditorSelection .code-line {
position: relative;
}
.notebook-preview .showEditorSelection .code-active-line:before,
.notebook-preview .showEditorSelection .code-line:hover:before {
content: "";
display: block;
position: absolute;
top: 0;
left: -12px;
height: 100%;
}
.notebook-preview .showEditorSelection li.code-active-line:before,
.notebook-preview .showEditorSelection li.code-line:hover:before {
left: -30px;
}
.notebook-preview .showEditorSelection .code-active-line:before {
border-left: 3px solid rgba(0, 0, 0, 0.15);
}
.notebook-preview .showEditorSelection .code-line:hover:before {
border-left: 3px solid rgba(0, 0, 0, 0.40);
}
.notebook-preview .showEditorSelection .code-line .code-line:hover:before {
border-left: none;
}
.vs-dark .notebook-preview .showEditorSelection .code-active-line:before {
border-left: 3px solid rgba(255, 255, 255, 0.4);
}
.vs-dark .notebook-preview .showEditorSelection .code-line:hover:before {
border-left: 3px solid rgba(255, 255, 255, 0.60);
}
.vs-dark .notebook-preview .showEditorSelection .code-line .code-line:hover:before {
border-left: none;
}
.hc-black .notebook-preview .showEditorSelection .code-active-line:before {
border-left: 3px solid rgba(255, 160, 0, 0.7);
}
.hc-black .notebook-preview .showEditorSelection .code-line:hover:before {
border-left: 3px solid rgba(255, 160, 0, 1);
}
.hc-black .notebook-preview .showEditorSelection .code-line .code-line:hover:before {
border-left: none;
}
.notebook-preview img {
max-width: 100%;
max-height: 100%;
}
.notebookEditor a {
text-decoration: none;
}
.notebookEditor a:hover {
text-decoration: underline;
}
.notebook-preview a:focus,
.notebook-preview input:focus,
.notebook-preview select:focus,
.notebook-preview textarea:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px;
}
.notebook-preview hr {
border: 0;
height: 2px;
border-bottom: 2px solid;
}
.notebook-preview h1 {
padding-bottom: 0.3em;
line-height: 1.2;
border-bottom-width: 1px;
border-bottom-style: solid;
}
.notebook-preview h1, .notebook-preview h2, .notebook-preview h3 {
font-weight: normal;
}
.notebook-preview h1 code,
.notebook-preview h2 code,
.notebook-preview h3 code,
.notebook-preview h4 code,
.notebook-preview h5 code,
.notebook-preview h6 code {
font-size: inherit;
line-height: auto;
}
.notebook-preview table {
border-collapse: collapse;
}
.notebook-preview table > thead > tr > th {
text-align: left;
border-bottom: 1px solid;
}
.notebook-preview table > thead > tr > th,
.notebook-preview table > thead > tr > td,
.notebook-preview table > tbody > tr > th,
.notebook-preview .notebook-preview table > tbody > tr > td {
padding: 5px 10px;
}
.notebook-preview table > tbody > tr + tr > td {
border-top: 1px solid;
}
.notebook-preview blockquote {
margin: 0 7px 0 5px;
padding: 0 16px 0 10px;
border-left-width: 5px;
border-left-style: solid;
}
.notebook-preview code {
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
font-size: 12px;
line-height: 19px;
}
.notebook-preview pre {
white-space: pre-wrap;
}
.notebook-preview .mac code {
font-size: 12px;
line-height: 18px;
}
.notebook-preview pre:not(.hljs),
.notebook-preview pre.hljs code > div {
padding: 16px;
border-radius: 3px;
overflow: auto;
}
/** Theming */
.notebook-preview pre code {
color: var(--vscode-editor-foreground);
}
.notebook-preview pre {
background-color: rgba(220, 220, 220, 0.4);
}
.vs-dark .notebook-preview pre {
background-color: rgba(10, 10, 10, 0.4);
}
.hc-black .notebook-preview pre {
background-color: rgb(0, 0, 0);
}
.hc-black .notebook-preview h1 {
border-color: rgb(0, 0, 0);
}
.notebook-preview table > thead > tr > th {
border-color: rgba(0, 0, 0, 0.69);
}
.vs-dark .notebook-preview table > thead > tr > th {
border-color: rgba(255, 255, 255, 0.69);
}
.notebook-preview h1,
.notebook-preview hr,
.notebook-preview table > tbody > tr + tr > td {
border-color: rgba(0, 0, 0, 0.18);
}
.vs-dark .notebook-preview h1,
.vs-dark .notebook-preview hr,
.vs-dark .notebook-preview table > tbody > tr + tr > td {
border-color: rgba(255, 255, 255, 0.18);
}

View File

@@ -3,6 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./textCell';
import 'vs/css!./media/markdown';
import 'vs/css!./media/highlight';
import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, OnChanges, SimpleChange, HostListener, AfterContentInit } from '@angular/core';
import * as path from 'path';
@@ -66,6 +68,7 @@ export class TextCellComponent extends CellView implements OnInit, AfterContentI
}
private _content: string;
private _lastTrustedMode: boolean;
private isEditMode: boolean;
private _sanitizer: ISanitizer;
private _model: NotebookModel;
@@ -192,15 +195,19 @@ export class TextCellComponent extends CellView implements OnInit, AfterContentI
* Sanitizes the data to be shown in markdown cell
*/
private updatePreview() {
if (this._content !== this.cellModel.source || this.cellModel.source.length === 0) {
let trustedChanged = this.cellModel && this._lastTrustedMode !== this.cellModel.trustedMode;
let contentChanged = this._content !== this.cellModel.source || this.cellModel.source.length === 0;
if (trustedChanged || contentChanged) {
this._lastTrustedMode = this.cellModel.trustedMode;
if (!this.cellModel.source && !this.isEditMode) {
this._content = localize('doubleClickEdit', 'Double-click to edit');
} else {
this._content = this.sanitizeContent(this.cellModel.source);
this._content = this.cellModel.source;
}
this._commandService.executeCommand<string>('notebook.showPreview', this.cellModel.notebookModel.notebookUri, this._content).then((htmlcontent) => {
htmlcontent = this.convertVscodeResourceToFileInSubDirectories(htmlcontent);
htmlcontent = this.sanitizeContent(htmlcontent);
let outputElement = <HTMLElement>this.output.nativeElement;
outputElement.innerHTML = htmlcontent;
});
@@ -214,7 +221,6 @@ export class TextCellComponent extends CellView implements OnInit, AfterContentI
}
return content;
}
// Only replace vscode-resource with file when in the same (or a sub) directory
// This matches Jupyter Notebook viewer behavior
private convertVscodeResourceToFileInSubDirectories(htmlContent: string): string {

View File

@@ -6,7 +6,7 @@ import 'vs/css!./notebook';
import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { SIDE_BAR_BACKGROUND, SIDE_BAR_SECTION_HEADER_BACKGROUND, EDITOR_GROUP_HEADER_TABS_BACKGROUND } from 'vs/workbench/common/theme';
import { activeContrastBorder, contrastBorder, buttonBackground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
import { activeContrastBorder, contrastBorder, buttonBackground, textLinkForeground, textLinkActiveForeground, textPreformatForeground, textBlockQuoteBackground, textBlockQuoteBorder } from 'vs/platform/theme/common/colorRegistry';
import { IDisposable } from 'vscode-xterm';
import { editorLineHighlight, editorLineHighlightBorder } from 'vs/editor/common/view/editorColorRegistry';
@@ -179,8 +179,6 @@ export function registerNotebookThemes(overrideEditorThemeSetting: boolean): IDi
if (linkForeground) {
collector.addRule(`
.notebookEditor a:link {
text-decoration: none;
font-weight: bold;
color: ${linkForeground};
}
`);
@@ -195,5 +193,43 @@ export function registerNotebookThemes(overrideEditorThemeSetting: boolean): IDi
}
`);
}
// Styling for markdown cells & links in notebooks.
// This matches the values used by default in all web views
if (linkForeground) {
collector.addRule(`
.notebookEditor a:link {
color: ${linkForeground};
}
`);
}
let activeForeground = theme.getColor(textLinkActiveForeground);
if (activeForeground) {
collector.addRule(`
.notebookEditor a:hover {
color: ${activeForeground};
}
`);
}
let preformatForeground = theme.getColor(textPreformatForeground);
if (preformatForeground) {
collector.addRule(`
.notebook-preview code {
color: ${preformatForeground};
}
`);
}
let blockQuoteBackground = theme.getColor(textBlockQuoteBackground);
let blockQuoteBorder = theme.getColor(textBlockQuoteBorder);
if (preformatForeground) {
collector.addRule(`
.notebookEditor blockquote {
background: ${blockQuoteBackground};
border-color: ${blockQuoteBorder};
}
`);
}
});
}