Fix Markdown HTML issue (#658)
This change enables notebooks to escape HTML (which is a vector for malicious attacks).
We import `MarkdownCell` from the `@nteract/stateful-components` sources so that we can point it to the version of `@nteract/markdown` which contains [this fix](e19c7cc590
).
This is a temporary workaround from upgrading to `@nteract/stateful-components` to `7.0.0` which causes build and runtime issues see #599).
This commit is contained in:
parent
7bdc31aa67
commit
41800f9ee5
|
@ -2829,6 +2829,16 @@
|
||||||
"url": "^0.11.0"
|
"url": "^0.11.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/react": {
|
||||||
|
"version": "17.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.3.tgz",
|
||||||
|
"integrity": "sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg==",
|
||||||
|
"requires": {
|
||||||
|
"@types/prop-types": "*",
|
||||||
|
"@types/scheduler": "*",
|
||||||
|
"csstype": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"buffer": {
|
"buffer": {
|
||||||
"version": "5.7.1",
|
"version": "5.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
|
@ -2838,6 +2848,11 @@
|
||||||
"ieee754": "^1.1.13"
|
"ieee754": "^1.1.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"csstype": {
|
||||||
|
"version": "3.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz",
|
||||||
|
"integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g=="
|
||||||
|
},
|
||||||
"react": {
|
"react": {
|
||||||
"version": "17.0.1",
|
"version": "17.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz",
|
||||||
|
@ -3604,19 +3619,19 @@
|
||||||
"integrity": "sha512-6f675p3gzs7ZMAovzfOx+QOMNu1TGVT2aV5lPOwnPxJCM/APLpDRFcSoURwLA26CROlTTDEe10XweFzJgQ+VEQ=="
|
"integrity": "sha512-6f675p3gzs7ZMAovzfOx+QOMNu1TGVT2aV5lPOwnPxJCM/APLpDRFcSoURwLA26CROlTTDEe10XweFzJgQ+VEQ=="
|
||||||
},
|
},
|
||||||
"@nteract/markdown": {
|
"@nteract/markdown": {
|
||||||
"version": "4.4.0",
|
"version": "4.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@nteract/markdown/-/markdown-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@nteract/markdown/-/markdown-4.6.0.tgz",
|
||||||
"integrity": "sha512-Xd8sxPmW42HW2Nq0pz2XrFBARt4wmgA0IbLQ23pg7FRMzpt2Ed4EjfuJkcm9ylTreAt1NJcljIpN47vzBUIehQ==",
|
"integrity": "sha512-DIeUYSRsFlHlIJ+bz/w1ln/KKtwqr9LsYZ+Uj/2t7mlmYxeEW0JRBa/E51QqCVdEepjAlpg2XqfqNgjkZiFfvw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@nteract/mathjax": "^4.0.7",
|
"@nteract/mathjax": "^4.0.11",
|
||||||
"@nteract/presentational-components": "^3.3.11",
|
"@nteract/presentational-components": "^3.3.11",
|
||||||
"react-markdown": "^4.0.0"
|
"react-markdown": "^4.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nteract/presentational-components": {
|
"@nteract/presentational-components": {
|
||||||
"version": "3.4.8",
|
"version": "3.4.9",
|
||||||
"resolved": "https://registry.npmjs.org/@nteract/presentational-components/-/presentational-components-3.4.8.tgz",
|
"resolved": "https://registry.npmjs.org/@nteract/presentational-components/-/presentational-components-3.4.9.tgz",
|
||||||
"integrity": "sha512-gS0Gbxs/Z3mB9TCgz1CU5zBHChhOf3RhkLHsesNf/ljm7rRadzaaYa1NxcgugtxkcnVqt32angl9KfoCYb8R9A==",
|
"integrity": "sha512-fcCYOdBRFyuj9vvXnrr2L2ynqouHnexUxpzt5VGTs4Mf/72r93vksarBStw2BD19utCVci7Fb5z6tNkFgveAZA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@blueprintjs/core": "^3.7.0",
|
"@blueprintjs/core": "^3.7.0",
|
||||||
"@blueprintjs/select": "^3.2.0",
|
"@blueprintjs/select": "^3.2.0",
|
||||||
|
@ -5339,8 +5354,7 @@
|
||||||
"@types/prop-types": {
|
"@types/prop-types": {
|
||||||
"version": "15.5.8",
|
"version": "15.5.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.8.tgz",
|
||||||
"integrity": "sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw==",
|
"integrity": "sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"@types/puppeteer": {
|
"@types/puppeteer": {
|
||||||
"version": "5.4.3",
|
"version": "5.4.3",
|
||||||
|
@ -5358,30 +5372,26 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/react": {
|
"@types/react": {
|
||||||
"version": "17.0.0",
|
"version": "17.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.3.tgz",
|
||||||
"integrity": "sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==",
|
"integrity": "sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/prop-types": "*",
|
"@types/prop-types": "*",
|
||||||
|
"@types/scheduler": "*",
|
||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/prop-types": {
|
|
||||||
"version": "15.7.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
|
||||||
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
|
|
||||||
},
|
|
||||||
"csstype": {
|
"csstype": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz",
|
||||||
"integrity": "sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw=="
|
"integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/react-dom": {
|
"@types/react-dom": {
|
||||||
"version": "17.0.0",
|
"version": "17.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.3.tgz",
|
||||||
"integrity": "sha512-lUqY7OlkF/RbNtD5nIq7ot8NquXrdFrjSOR6+w9a9RFQevGi1oZO1dcJbXMeONAPKtZ2UrZOEJ5UOCVsxbLk/g==",
|
"integrity": "sha512-4NnJbCeWE+8YBzupn/YrJxZ8VnjcJq5iR1laqQ1vkpQgBiA7bwk0Rp24fxsdNinzJY2U+HHS4dJJDPdoMjdJ7w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
|
@ -5430,6 +5440,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
|
||||||
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="
|
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="
|
||||||
},
|
},
|
||||||
|
"@types/scheduler": {
|
||||||
|
"version": "0.16.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz",
|
||||||
|
"integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA=="
|
||||||
|
},
|
||||||
"@types/shallowequal": {
|
"@types/shallowequal": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/shallowequal/-/shallowequal-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/shallowequal/-/shallowequal-1.1.1.tgz",
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
"@nteract/iron-icons": "1.0.0",
|
"@nteract/iron-icons": "1.0.0",
|
||||||
"@nteract/jupyter-widgets": "2.0.0",
|
"@nteract/jupyter-widgets": "2.0.0",
|
||||||
"@nteract/logos": "1.0.0",
|
"@nteract/logos": "1.0.0",
|
||||||
"@nteract/markdown": "4.4.0",
|
"@nteract/markdown": "4.6.0",
|
||||||
"@nteract/monaco-editor": "3.2.2",
|
"@nteract/monaco-editor": "3.2.2",
|
||||||
"@nteract/octicons": "2.0.0",
|
"@nteract/octicons": "2.0.0",
|
||||||
"@nteract/outputs": "3.0.9",
|
"@nteract/outputs": "3.0.9",
|
||||||
|
@ -120,8 +120,8 @@
|
||||||
"@types/prop-types": "15.5.8",
|
"@types/prop-types": "15.5.8",
|
||||||
"@types/puppeteer": "5.4.3",
|
"@types/puppeteer": "5.4.3",
|
||||||
"@types/q": "1.5.1",
|
"@types/q": "1.5.1",
|
||||||
"@types/react": "17.0.0",
|
"@types/react": "17.0.3",
|
||||||
"@types/react-dom": "17.0.0",
|
"@types/react-dom": "17.0.3",
|
||||||
"@types/react-notification-system": "0.2.39",
|
"@types/react-notification-system": "0.2.39",
|
||||||
"@types/react-redux": "7.1.7",
|
"@types/react-redux": "7.1.7",
|
||||||
"@types/sinon": "2.3.3",
|
"@types/sinon": "2.3.3",
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { CellId } from "@nteract/commutable";
|
||||||
import { CellType } from "@nteract/commutable/src";
|
import { CellType } from "@nteract/commutable/src";
|
||||||
import { actions, ContentRef } from "@nteract/core";
|
import { actions, ContentRef } from "@nteract/core";
|
||||||
import { KernelOutputError, StreamText } from "@nteract/outputs";
|
import { KernelOutputError, StreamText } from "@nteract/outputs";
|
||||||
import { Cells, CodeCell, MarkdownCell, RawCell } from "@nteract/stateful-components";
|
import { Cells, CodeCell, RawCell } from "@nteract/stateful-components";
|
||||||
import MonacoEditor from "@nteract/stateful-components/lib/inputs/connected-editors/monacoEditor";
|
import MonacoEditor from "@nteract/stateful-components/lib/inputs/connected-editors/monacoEditor";
|
||||||
import { PassedEditorProps } from "@nteract/stateful-components/lib/inputs/editor";
|
import { PassedEditorProps } from "@nteract/stateful-components/lib/inputs/editor";
|
||||||
import TransformMedia from "@nteract/stateful-components/lib/outputs/transform-media";
|
import TransformMedia from "@nteract/stateful-components/lib/outputs/transform-media";
|
||||||
|
@ -21,6 +21,7 @@ import CellLabeler from "./decorators/CellLabeler";
|
||||||
import HoverableCell from "./decorators/HoverableCell";
|
import HoverableCell from "./decorators/HoverableCell";
|
||||||
import KeyboardShortcuts from "./decorators/kbd-shortcuts";
|
import KeyboardShortcuts from "./decorators/kbd-shortcuts";
|
||||||
import "./default.css";
|
import "./default.css";
|
||||||
|
import MarkdownCell from "./markdown-cell";
|
||||||
import "./NotebookRenderer.less";
|
import "./NotebookRenderer.less";
|
||||||
import IFrameOutputs from "./outputs/IFrameOutputs";
|
import IFrameOutputs from "./outputs/IFrameOutputs";
|
||||||
import Prompt from "./Prompt";
|
import Prompt from "./Prompt";
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
// TODO The purpose of importing this source file https://github.com/nteract/nteract/blob/main/packages/stateful-components/src/cells/markdown-cell.tsx
|
||||||
|
// into our source is to be able to overwrite the version of react-markdown which has this fix ("escape html to false")
|
||||||
|
// https://github.com/nteract/markdown/commit/e19c7cc590a4379fc507f67a7b4228363b9d8631 without having to upgrade
|
||||||
|
// @nteract/stateful-component which causes runtime issues.
|
||||||
|
|
||||||
|
import { ImmutableCell } from "@nteract/commutable/src";
|
||||||
|
import { actions, AppState, ContentRef, selectors } from "@nteract/core";
|
||||||
|
import { MarkdownPreviewer } from "@nteract/markdown";
|
||||||
|
import { defineConfigOption } from "@nteract/mythic-configuration";
|
||||||
|
import { Source } from "@nteract/presentational-components";
|
||||||
|
import Editor, { EditorSlots } from "@nteract/stateful-components/lib/inputs/editor";
|
||||||
|
import React from "react";
|
||||||
|
import { ReactMarkdownProps } from "react-markdown";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { Dispatch } from "redux";
|
||||||
|
|
||||||
|
const { selector: markdownConfig } = defineConfigOption({
|
||||||
|
key: "markdownOptions",
|
||||||
|
label: "Markdown Editor Options",
|
||||||
|
defaultValue: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
interface NamedMDCellSlots {
|
||||||
|
editor?: EditorSlots;
|
||||||
|
toolbar?: () => JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ComponentProps {
|
||||||
|
id: string;
|
||||||
|
contentRef: ContentRef;
|
||||||
|
cell_type?: "markdown";
|
||||||
|
children?: NamedMDCellSlots;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StateProps {
|
||||||
|
isCellFocused: boolean;
|
||||||
|
isEditorFocused: boolean;
|
||||||
|
cell?: ImmutableCell;
|
||||||
|
markdownOptions: ReactMarkdownProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DispatchProps {
|
||||||
|
focusAboveCell: () => void;
|
||||||
|
focusBelowCell: () => void;
|
||||||
|
focusEditor: () => void;
|
||||||
|
unfocusEditor: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PureMarkdownCell extends React.Component<ComponentProps & DispatchProps & StateProps> {
|
||||||
|
render() {
|
||||||
|
const { contentRef, id, cell, children } = this.props;
|
||||||
|
|
||||||
|
const { isEditorFocused, isCellFocused, markdownOptions } = this.props;
|
||||||
|
|
||||||
|
const { focusAboveCell, focusBelowCell, focusEditor, unfocusEditor } = this.props;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We don't set the editor slots as defaults to support dynamic imports
|
||||||
|
* Users can continue to add the editorSlots as children
|
||||||
|
*/
|
||||||
|
const editor = children?.editor;
|
||||||
|
const toolbar = children?.toolbar;
|
||||||
|
|
||||||
|
const source = cell ? cell.get("source", "") : "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="nteract-md-cell nteract-cell">
|
||||||
|
<div className="nteract-cell-row">
|
||||||
|
<div className="nteract-cell-gutter">{toolbar && toolbar()}</div>
|
||||||
|
<div className="nteract-cell-body">
|
||||||
|
<MarkdownPreviewer
|
||||||
|
focusAbove={focusAboveCell}
|
||||||
|
focusBelow={focusBelowCell}
|
||||||
|
focusEditor={focusEditor}
|
||||||
|
cellFocused={isCellFocused}
|
||||||
|
editorFocused={isEditorFocused}
|
||||||
|
unfocusEditor={unfocusEditor}
|
||||||
|
source={source}
|
||||||
|
markdownOptions={markdownOptions}
|
||||||
|
>
|
||||||
|
<Source className="nteract-cell-source">
|
||||||
|
<Editor id={id} contentRef={contentRef}>
|
||||||
|
{editor}
|
||||||
|
</Editor>
|
||||||
|
</Source>
|
||||||
|
</MarkdownPreviewer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const makeMapStateToProps = (
|
||||||
|
initialState: AppState,
|
||||||
|
ownProps: ComponentProps
|
||||||
|
): ((state: AppState) => StateProps) => {
|
||||||
|
const { id, contentRef } = ownProps;
|
||||||
|
const mapStateToProps = (state: AppState): StateProps => {
|
||||||
|
const model = selectors.model(state, { contentRef });
|
||||||
|
let isCellFocused = false;
|
||||||
|
let isEditorFocused = false;
|
||||||
|
let cell;
|
||||||
|
|
||||||
|
if (model && model.type === "notebook") {
|
||||||
|
cell = selectors.notebook.cellById(model, { id });
|
||||||
|
isCellFocused = model.cellFocused === id;
|
||||||
|
isEditorFocused = model.editorFocused === id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const markdownOptionsDefaults = {
|
||||||
|
linkTarget: "_blank",
|
||||||
|
};
|
||||||
|
const currentMarkdownOptions = markdownConfig(state);
|
||||||
|
|
||||||
|
const markdownOptions = Object.assign({}, markdownOptionsDefaults, currentMarkdownOptions);
|
||||||
|
|
||||||
|
return {
|
||||||
|
cell,
|
||||||
|
isCellFocused,
|
||||||
|
isEditorFocused,
|
||||||
|
markdownOptions,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return mapStateToProps;
|
||||||
|
};
|
||||||
|
|
||||||
|
const makeMapDispatchToProps = (
|
||||||
|
initialDispatch: Dispatch,
|
||||||
|
ownProps: ComponentProps
|
||||||
|
): ((dispatch: Dispatch) => DispatchProps) => {
|
||||||
|
const { id, contentRef } = ownProps;
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
|
||||||
|
focusAboveCell: () => {
|
||||||
|
dispatch(actions.focusPreviousCell({ id, contentRef }));
|
||||||
|
dispatch(actions.focusPreviousCellEditor({ id, contentRef }));
|
||||||
|
},
|
||||||
|
focusBelowCell: () => {
|
||||||
|
dispatch(actions.focusNextCell({ id, createCellIfUndefined: true, contentRef }));
|
||||||
|
dispatch(actions.focusNextCellEditor({ id, contentRef }));
|
||||||
|
},
|
||||||
|
focusEditor: () => dispatch(actions.focusCellEditor({ id, contentRef })),
|
||||||
|
unfocusEditor: () => dispatch(actions.focusCellEditor({ id: undefined, contentRef })),
|
||||||
|
});
|
||||||
|
|
||||||
|
return mapDispatchToProps;
|
||||||
|
};
|
||||||
|
|
||||||
|
const MarkdownCell = connect(makeMapStateToProps, makeMapDispatchToProps)(PureMarkdownCell);
|
||||||
|
|
||||||
|
export default MarkdownCell;
|
Loading…
Reference in New Issue