diff --git a/__tests__/src/components/SanitizedHtml.test.js b/__tests__/src/components/SanitizedHtml.test.js new file mode 100644 index 0000000000000000000000000000000000000000..c630c0f730de542f049db6608872a7ca7bfb289f --- /dev/null +++ b/__tests__/src/components/SanitizedHtml.test.js @@ -0,0 +1,25 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import SanitizedHtml from '../../../src/components/SanitizedHtml'; + +const wrapper = shallow( + <SanitizedHtml + htmlString="<script>doBadThings()</script><b>Don't worry!</b>" + ruleSet="basic" + />, +); + +describe('SanitizedHtml', () => { + it('should render needed elements', () => { + expect(wrapper.find('span').length).toBe(1); + }); + + it('should pass correct class name to root element', () => { + expect(wrapper.find('span').first().props().className).toBe('mirador-third-party-html'); + }); + + it('should pass sanitized html string to dangerouslySetInnerHTML attribute', () => { + expect(wrapper.find('span').first().props().dangerouslySetInnerHTML) + .toEqual({ __html: "<b>Don't worry!</b>" }); + }); +}); diff --git a/package.json b/package.json index a145b294270e2a829a2cd86353392ce4e75f65a7..7e05e1af0cb79546caeed11726a9fd320f39632c 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "classnames": "^2.2.6", "css-ns": "^1.2.2", "deepmerge": "^3.1.0", + "dompurify": "^1.0.9", "i18next": "^14.0.1", "intersection-observer": "^0.5.1", "manifesto.js": "^3.0.9", diff --git a/src/components/SanitizedHtml.js b/src/components/SanitizedHtml.js new file mode 100644 index 0000000000000000000000000000000000000000..299bf2eab8f6b93699e9ee2bac4a9b445f39ef5a --- /dev/null +++ b/src/components/SanitizedHtml.js @@ -0,0 +1,30 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { sanitize } from 'dompurify'; +import ns from '../config/css-ns'; +import htmlRules from '../lib/htmlRules'; + +/** +*/ +class SanitizedHtml extends Component { + /** + */ + render() { + const { htmlString, ruleSet } = this.props; + return ( + <span + className={ns('third-party-html')} + dangerouslySetInnerHTML={{ // eslint-disable-line react/no-danger + __html: sanitize(htmlString, htmlRules[ruleSet]), + }} + /> + ); + } +} + +SanitizedHtml.propTypes = { + ruleSet: PropTypes.string.isRequired, + htmlString: PropTypes.string.isRequired, +}; + +export default SanitizedHtml; diff --git a/src/lib/htmlRules.js b/src/lib/htmlRules.js new file mode 100644 index 0000000000000000000000000000000000000000..ca5b95dd9e7956234c0cc6870ccdd439f26705dc --- /dev/null +++ b/src/lib/htmlRules.js @@ -0,0 +1,7 @@ + +const basic = { + ALLOWED_TAGS: ['a', 'b', 'br', 'i', 'img', 'p', 'span', 'strong', 'em', 'ul', 'ol', 'li'], + ALLOWED_ATTR: ['href', 'target', 'src', 'alt', 'dir'], +}; + +export default { basic };