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"
|
||||
},
|
||||
"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": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
|
@ -2838,6 +2848,11 @@
|
|||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"csstype": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz",
|
||||
"integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g=="
|
||||
},
|
||||
"react": {
|
||||
"version": "17.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz",
|
||||
|
@ -3604,19 +3619,19 @@
|
|||
"integrity": "sha512-6f675p3gzs7ZMAovzfOx+QOMNu1TGVT2aV5lPOwnPxJCM/APLpDRFcSoURwLA26CROlTTDEe10XweFzJgQ+VEQ=="
|
||||
},
|
||||
"@nteract/markdown": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@nteract/markdown/-/markdown-4.4.0.tgz",
|
||||
"integrity": "sha512-Xd8sxPmW42HW2Nq0pz2XrFBARt4wmgA0IbLQ23pg7FRMzpt2Ed4EjfuJkcm9ylTreAt1NJcljIpN47vzBUIehQ==",
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@nteract/markdown/-/markdown-4.6.0.tgz",
|
||||
"integrity": "sha512-DIeUYSRsFlHlIJ+bz/w1ln/KKtwqr9LsYZ+Uj/2t7mlmYxeEW0JRBa/E51QqCVdEepjAlpg2XqfqNgjkZiFfvw==",
|
||||
"requires": {
|
||||
"@nteract/mathjax": "^4.0.7",
|
||||
"@nteract/mathjax": "^4.0.11",
|
||||
"@nteract/presentational-components": "^3.3.11",
|
||||
"react-markdown": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nteract/presentational-components": {
|
||||
"version": "3.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@nteract/presentational-components/-/presentational-components-3.4.8.tgz",
|
||||
"integrity": "sha512-gS0Gbxs/Z3mB9TCgz1CU5zBHChhOf3RhkLHsesNf/ljm7rRadzaaYa1NxcgugtxkcnVqt32angl9KfoCYb8R9A==",
|
||||
"version": "3.4.9",
|
||||
"resolved": "https://registry.npmjs.org/@nteract/presentational-components/-/presentational-components-3.4.9.tgz",
|
||||
"integrity": "sha512-fcCYOdBRFyuj9vvXnrr2L2ynqouHnexUxpzt5VGTs4Mf/72r93vksarBStw2BD19utCVci7Fb5z6tNkFgveAZA==",
|
||||
"requires": {
|
||||
"@blueprintjs/core": "^3.7.0",
|
||||
"@blueprintjs/select": "^3.2.0",
|
||||
|
@ -5339,8 +5354,7 @@
|
|||
"@types/prop-types": {
|
||||
"version": "15.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.8.tgz",
|
||||
"integrity": "sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw=="
|
||||
},
|
||||
"@types/puppeteer": {
|
||||
"version": "5.4.3",
|
||||
|
@ -5358,30 +5372,26 @@
|
|||
"dev": true
|
||||
},
|
||||
"@types/react": {
|
||||
"version": "17.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.0.tgz",
|
||||
"integrity": "sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==",
|
||||
"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"
|
||||
},
|
||||
"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": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.6.tgz",
|
||||
"integrity": "sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw=="
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz",
|
||||
"integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"version": "17.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.0.tgz",
|
||||
"integrity": "sha512-lUqY7OlkF/RbNtD5nIq7ot8NquXrdFrjSOR6+w9a9RFQevGi1oZO1dcJbXMeONAPKtZ2UrZOEJ5UOCVsxbLk/g==",
|
||||
"version": "17.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.3.tgz",
|
||||
"integrity": "sha512-4NnJbCeWE+8YBzupn/YrJxZ8VnjcJq5iR1laqQ1vkpQgBiA7bwk0Rp24fxsdNinzJY2U+HHS4dJJDPdoMjdJ7w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
|
@ -5430,6 +5440,11 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
|
||||
"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": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/shallowequal/-/shallowequal-1.1.1.tgz",
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
"@nteract/iron-icons": "1.0.0",
|
||||
"@nteract/jupyter-widgets": "2.0.0",
|
||||
"@nteract/logos": "1.0.0",
|
||||
"@nteract/markdown": "4.4.0",
|
||||
"@nteract/markdown": "4.6.0",
|
||||
"@nteract/monaco-editor": "3.2.2",
|
||||
"@nteract/octicons": "2.0.0",
|
||||
"@nteract/outputs": "3.0.9",
|
||||
|
@ -120,8 +120,8 @@
|
|||
"@types/prop-types": "15.5.8",
|
||||
"@types/puppeteer": "5.4.3",
|
||||
"@types/q": "1.5.1",
|
||||
"@types/react": "17.0.0",
|
||||
"@types/react-dom": "17.0.0",
|
||||
"@types/react": "17.0.3",
|
||||
"@types/react-dom": "17.0.3",
|
||||
"@types/react-notification-system": "0.2.39",
|
||||
"@types/react-redux": "7.1.7",
|
||||
"@types/sinon": "2.3.3",
|
||||
|
|
|
@ -2,7 +2,7 @@ import { CellId } from "@nteract/commutable";
|
|||
import { CellType } from "@nteract/commutable/src";
|
||||
import { actions, ContentRef } from "@nteract/core";
|
||||
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 { PassedEditorProps } from "@nteract/stateful-components/lib/inputs/editor";
|
||||
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 KeyboardShortcuts from "./decorators/kbd-shortcuts";
|
||||
import "./default.css";
|
||||
import MarkdownCell from "./markdown-cell";
|
||||
import "./NotebookRenderer.less";
|
||||
import IFrameOutputs from "./outputs/IFrameOutputs";
|
||||
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