Skip to content

Commit

Permalink
feat: move from allowlists to DOMPurify on text
Browse files Browse the repository at this point in the history
Closes #642
  • Loading branch information
Skaiir committed Jan 22, 2024
1 parent c80c5d4 commit 5b67d11
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 66 deletions.
25 changes: 12 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/form-js-carbon-styles/src/carbon-styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@

// Markdown styles /////////////

.fjs-container .fjs-form-field.fjs-form-field-text .markup {
.fjs-container .fjs-form-field.fjs-form-field-text {
font-size: var(--cds-body-long-01-font-size);
font-weight: var(--cds-body-long-01-font-weight);
line-height: var(--cds-body-long-01-line-height);
Expand Down
2 changes: 1 addition & 1 deletion packages/form-js-viewer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@
"big.js": "^6.2.1",
"classnames": "^2.3.1",
"didi": "^10.0.1",
"dompurify": "^3.0.8",
"feelers": "^1.2.0",
"feelin": "^3.0.0",
"flatpickr": "^4.6.13",
"ids": "^1.0.0",
"lodash": "^4.5.0",
"min-dash": "^4.0.0",
"preact": "^10.5.14",
"preact-markup": "^2.1.1",
"showdown": "^2.1.0"
},
"sideEffects": [
Expand Down
1 change: 0 additions & 1 deletion packages/form-js-viewer/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ export default [
'preact/jsx-runtime',
'preact/hooks',
'preact/compat',
'preact-markup',
'flatpickr',
'showdown',
'@carbon/grid',
Expand Down
51 changes: 22 additions & 29 deletions packages/form-js-viewer/src/render/components/form-fields/Text.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Markup from 'preact-markup';
import { useMemo } from 'preact/hooks';
import { useCallback, useMemo } from 'preact/hooks';
import { useService, useTemplateEvaluation } from '../../hooks';
import { sanitizeHTML } from '../Sanitizer';
import { SanitizedRawHTMLRenderer } from './parts/SanitizedRawHTMLRenderer';

import {
formFieldClasses
Expand All @@ -19,33 +18,35 @@ export function Text(props) {
const { text = '', strict = false } = field;

const markdownRenderer = useService('markdownRenderer');

// feelers => pure markdown
const markdown = useTemplateEvaluation(text, { debug: true, strict });
const html = useMemo(() => markdownRenderer.render(markdown), [ markdownRenderer, markdown ]);

const transformLinks = useCallback((html) => {

const tempDiv = document.createElement('div');
tempDiv.innerHTML = html;

const links = tempDiv.querySelectorAll('a');

// markdown => safe HTML
const safeHtml = useMemo(() => {
const html = markdownRenderer.render(markdown);
return sanitizeHTML(html);
}, [ markdownRenderer, markdown ]);
links.forEach(link => {

const OverriddenTargetLink = useMemo(() => BuildOverriddenTargetLink(textLinkTarget), [ textLinkTarget ]);
if (disableLinks) {
link.setAttribute('class', 'fjs-disabled-link');
link.setAttribute('tabIndex', '-1');
}

const componentOverrides = useMemo(() => {
if (textLinkTarget) {
link.setAttribute('target', textLinkTarget);
}

if (disableLinks) {
return { 'a': DisabledLink };
}
});

if (textLinkTarget) {
return { 'a': OverriddenTargetLink };
}
return tempDiv.innerHTML;

return {};
}, [ disableLinks, OverriddenTargetLink, textLinkTarget ]);
}, [ disableLinks, textLinkTarget ]);

return <div class={ formFieldClasses(type) }>
<Markup markup={ safeHtml } components={ componentOverrides } trim={ false } />
<SanitizedRawHTMLRenderer html={ html } transform={ transformLinks } />
</div>;
}

Expand All @@ -59,11 +60,3 @@ Text.config = {
...options
})
};

function BuildOverriddenTargetLink(target) {
return function({ children, ...rest }) {
return <a { ...rest } target={ target }>{ children }</a>;
};
}

function DisabledLink({ children, ...rest }) { return <a { ...rest } class="fjs-disabled-link" tabIndex={ -1 }>{ children }</a>; }
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import DOMPurify from 'dompurify';
import { useMemo } from 'preact/hooks';

export const SanitizedRawHTMLRenderer = ({ html, transform = (html) => html }) => {
const sanitizedHtml = DOMPurify.sanitize(html);
const tranformedHtml = useMemo(() => transform(sanitizedHtml), [ sanitizedHtml, transform ]);

return <div dangerouslySetInnerHTML={ { __html: tranformedHtml } } />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql(`<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><h1 id="h1">h1</h1>
expect(formField.innerHTML).to.eql(`<div><h1 id="h1">h1</h1>
<h2 id="h2">h2</h2>
<h3 id="h3">h3</h3>
<h4 id="h4">h4</h4>
Expand All @@ -102,7 +102,7 @@ Some _em_ **strong** [text](#text) \`code\`.
<pre><code>Some Code</code></pre>
<p>Some <em>em</em> <strong>strong</strong> <a href="#text">text</a> <code>code</code>.</p>
<hr>
<p><img alt="Image" src="#"></p></div></div>`);
<p><img alt="Image" src="#"></p></div>`);

});

Expand Down Expand Up @@ -178,7 +178,7 @@ Some _em_ **strong** [text](#text) \`code\`.

expect(formField).to.exist;
expect(formField.classList.contains('fjs-form-field-text')).to.be.true;
expect(formField.innerHTML).to.equal('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"></div></div>');
expect(formField.innerHTML).to.equal('<div></div>');
});


Expand All @@ -199,7 +199,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><h1 id="foo">foo</h1></div></div>');
expect(formField.innerHTML).to.eql('<div><h1 id="foo">foo</h1></div>');
});


Expand All @@ -216,7 +216,7 @@ Some _em_ **strong** [text](#text) \`code\`.
// then
const formField = container.querySelector('.fjs-form-field');

const expected = `<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><table>
const expected = `<div><table>
<thead>
<tr>
<th id="foo">foo</th>
Expand All @@ -229,7 +229,7 @@ Some _em_ **strong** [text](#text) \`code\`.
<td>qux</td>
</tr>
</tbody>
</table></div></div>`;
</table></div>`;

expect(formField).to.exist;
expect(formField.innerHTML).to.eql(expected);
Expand Down Expand Up @@ -258,7 +258,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><h1>foo</h1></div></div>');
expect(formField.innerHTML).to.eql('<div><h1>foo</h1></div>');
});


Expand All @@ -278,7 +278,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><p>["#foo", "###bar"]</p></div></div>');
expect(formField.innerHTML).to.eql('<div><p>["#foo", "###bar"]</p></div>');
});


Expand Down Expand Up @@ -330,7 +330,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><p>foo</p></div></div>');
expect(formField.innerHTML).to.eql('<div><p>foo</p></div>');
});


Expand All @@ -354,7 +354,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><p>bar</p></div></div>');
expect(formField.innerHTML).to.eql('<div><p>bar</p></div>');
});


Expand All @@ -378,7 +378,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><h1 id="bar">bar</h1></div></div>');
expect(formField.innerHTML).to.eql('<div><h1 id="bar">bar</h1></div>');

});

Expand All @@ -403,7 +403,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><p>foo bar</p></div></div>');
expect(formField.innerHTML).to.eql('<div><p>foo bar</p></div>');

});

Expand All @@ -428,7 +428,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><h1 id="bar-foo">bar foo</h1></div></div>');
expect(formField.innerHTML).to.eql('<div><h1 id="bar-foo">bar foo</h1></div>');

});

Expand All @@ -453,7 +453,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><p>foo bar</p></div></div>');
expect(formField.innerHTML).to.eql('<div><p>foo bar</p></div>');

});

Expand All @@ -478,7 +478,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><p>foo </p></div></div>');
expect(formField.innerHTML).to.eql('<div><p>foo </p></div>');

});

Expand All @@ -503,7 +503,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><h1 id="foo-bar">foo bar</h1></div></div>');
expect(formField.innerHTML).to.eql('<div><h1 id="foo-bar">foo bar</h1></div>');
});


Expand All @@ -527,7 +527,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><p>foo barbarbar</p></div></div>');
expect(formField.innerHTML).to.eql('<div><p>foo barbarbar</p></div>');
});


Expand All @@ -551,7 +551,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><h1 id="foo-barbarbar">foo barbarbar</h1></div></div>');
expect(formField.innerHTML).to.eql('<div><h1 id="foo-barbarbar">foo barbarbar</h1></div>');
});


Expand All @@ -575,7 +575,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><p>foo abc</p></div></div>');
expect(formField.innerHTML).to.eql('<div><p>foo abc</p></div>');
});


Expand All @@ -601,7 +601,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><p>foo {{⚠}} </p></div></div>');
expect(formField.innerHTML).to.eql('<div><p>foo {{⚠}} </p></div>');

});

Expand Down Expand Up @@ -629,7 +629,7 @@ Some _em_ **strong** [text](#text) \`code\`.
const formField = container.querySelector('.fjs-form-field');

expect(formField).to.exist;
expect(formField.innerHTML).to.eql('<div class="markup"><div xmlns="http://www.w3.org/1999/xhtml"><p>EVALUATED:myTemplate</p></div></div>');
expect(formField.innerHTML).to.eql('<div><p>EVALUATED:myTemplate</p></div>');
});

});
Expand Down

0 comments on commit 5b67d11

Please sign in to comment.