fix(security-markdown-widget): allow sanitization of preview content (#4886)
This commit is contained in:
parent
da31332641
commit
27aec85550
@ -22,6 +22,7 @@
|
||||
"build:esm": "cross-env NODE_ENV=esm babel src --out-dir dist/esm --ignore \"**/__tests__\" --root-mode upward"
|
||||
},
|
||||
"dependencies": {
|
||||
"dompurify": "^2.2.6",
|
||||
"is-hotkey": "^0.2.0",
|
||||
"mdast-util-definitions": "^1.2.3",
|
||||
"mdast-util-to-string": "^1.0.5",
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { WidgetPreviewContainer } from 'netlify-cms-ui-default';
|
||||
import { markdownToHtml } from './serializers';
|
||||
|
||||
import DOMPurify from 'dompurify';
|
||||
class MarkdownPreview extends React.Component {
|
||||
static propTypes = {
|
||||
getAsset: PropTypes.func.isRequired,
|
||||
@ -11,14 +11,15 @@ class MarkdownPreview extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { value, getAsset, resolveWidget } = this.props;
|
||||
const { value, getAsset, resolveWidget, field } = this.props;
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const html = markdownToHtml(value, { getAsset, resolveWidget });
|
||||
const toRender = field?.get('sanitize_preview', false) ? DOMPurify.sanitize(html) : html;
|
||||
|
||||
return <WidgetPreviewContainer dangerouslySetInnerHTML={{ __html: html }} />;
|
||||
return <WidgetPreviewContainer dangerouslySetInnerHTML={{ __html: toRender }} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,36 @@ exports[`Markdown Preview renderer HTML rendering should render HTML 1`] = `
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`Markdown Preview renderer HTML sanitization should not sanitize HTML 1`] = `
|
||||
.emotion-0 {
|
||||
margin: 15px 2px;
|
||||
}
|
||||
|
||||
<div
|
||||
className="emotion-0 emotion-1"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "<img src=\\"foobar.png\\" onerror=\\"alert('hello')\\">",
|
||||
}
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`Markdown Preview renderer HTML sanitization should sanitize HTML 1`] = `
|
||||
.emotion-0 {
|
||||
margin: 15px 2px;
|
||||
}
|
||||
|
||||
<div
|
||||
className="emotion-0 emotion-1"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "<img src=\\"foobar.png\\">",
|
||||
}
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`Markdown Preview renderer Markdown rendering Code should render code 1`] = `
|
||||
.emotion-0 {
|
||||
margin: 15px 2px;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { create, act } from 'react-test-renderer';
|
||||
import { padStart } from 'lodash';
|
||||
import { Map } from 'immutable';
|
||||
import MarkdownPreview from '../MarkdownPreview';
|
||||
import { markdownToHtml } from '../serializers';
|
||||
|
||||
@ -216,4 +217,44 @@ I get 10 times more traffic from [Google] than from [Yahoo] or [MSN].
|
||||
expect(root.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('HTML sanitization', () => {
|
||||
it('should sanitize HTML', async () => {
|
||||
const value = `<img src="foobar.png" onerror="alert('hello')">`;
|
||||
const field = Map({ sanitize_preview: true });
|
||||
|
||||
let root;
|
||||
await act(async () => {
|
||||
root = create(
|
||||
<MarkdownPreview
|
||||
value={value}
|
||||
getAsset={jest.fn()}
|
||||
resolveWidget={jest.fn()}
|
||||
field={field}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
expect(root.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should not sanitize HTML', async () => {
|
||||
const value = `<img src="foobar.png" onerror="alert('hello')">`;
|
||||
const field = Map({ sanitize_preview: false });
|
||||
|
||||
let root;
|
||||
await act(async () => {
|
||||
root = create(
|
||||
<MarkdownPreview
|
||||
value={value}
|
||||
getAsset={jest.fn()}
|
||||
resolveWidget={jest.fn()}
|
||||
field={field}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
expect(root.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -16,6 +16,7 @@ The markdown widget provides a full fledged text editor allowing users to format
|
||||
* `buttons`: an array of strings representing the formatting buttons to display (all shown by default). Buttons include: `bold`, `italic`, `code`, `link`, `heading-one`, `heading-two`, `heading-three`, `heading-four`, `heading-five`, `heading-six`, `quote`, `bulleted-list`, and `numbered-list`.
|
||||
* `editor_components`: an array of strings representing the names of editor components to display (all shown by default). Netlify CMS includes `image` and `code-block` editor components by default, and custom components may be [created and registered](/docs/custom-widgets/#registereditorcomponent).
|
||||
* `modes`: an array of strings representing the names of allowed editor modes. Possible modes are `raw` and `rich_text`. A toggle button appears in the toolbar when more than one mode is available.
|
||||
* `sanitize_preview`: accepts a boolean value, `false` by default. Sanitizes markdown preview to prevent XSS attacks - might alter the preview content.
|
||||
* **Example:**
|
||||
|
||||
```yaml
|
||||
@ -26,4 +27,4 @@ This would render as:
|
||||
|
||||

|
||||
|
||||
*Please note:* The markdown widget outputs a raw markdown string. Your static site generator may or may not render the markdown to HTML automatically. Consult with your static site generator's documentation for more information about rendering markdown.
|
||||
*Please note:* The markdown widget outputs a raw markdown string. Your static site generator may or may not render the markdown to HTML automatically. Consult with your static site generator's documentation for more information about rendering markdown.
|
||||
|
@ -7313,6 +7313,11 @@ domhandler@^2.3.0:
|
||||
dependencies:
|
||||
domelementtype "1"
|
||||
|
||||
dompurify@^2.2.6:
|
||||
version "2.2.6"
|
||||
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.2.6.tgz#54945dc5c0b45ce5ae228705777e8e59d7b2edc4"
|
||||
integrity sha512-7b7ZArhhH0SP6W2R9cqK6RjaU82FZ2UPM7RO8qN1b1wyvC/NY1FNWcX1Pu00fFOAnzEORtwXe4bPaClg6pUybQ==
|
||||
|
||||
domutils@^1.5.1, domutils@^1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
|
||||
|
Loading…
x
Reference in New Issue
Block a user