Skip to content

Commit

Permalink
STSMACOM-816 for CSP #5 - Safely render markup in <Notes> component…
Browse files Browse the repository at this point in the history
…s. (#1473)

* STSMACOM-816 Safely render HTML in Note template (#1453)

* clean markup with dompurify.sanitize()

* log changes

* update lockfile

* filter html in noteslist

* log changes

* Update CHANGELOG.md
  • Loading branch information
JohnC-80 authored Apr 24, 2024
1 parent 9743159 commit 4d56b9e
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 4 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
# Change history for stripes-smart-components

## 9.0.3 In progress

* Safely render user-provided markup in `<NotesView>` and `<NotesList>` components. Fixes STSMACOM-816.

## [9.0.2](https://github.com/folio-org/stripes-smart-components/tree/v9.0.2) (2023-11-28)
[Full Changelog](https://github.com/folio-org/stripes-smart-components/compare/v9.0.1...v9.0.2)

* Send `X-Okapi-Token` header only when token is present in `stripes`. Refs STSMACOM-714.


## [9.0.1](https://github.com/folio-org/stripes-smart-components/tree/v9.0.1) (2023-10-25)
[Full Changelog](https://github.com/folio-org/stripes-smart-components/compare/v9.0.0...v9.0.1)

Expand Down
4 changes: 3 additions & 1 deletion lib/Notes/NoteViewPage/components/NoteView/NoteView.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import get from 'lodash/get';
import dompurify from 'dompurify';

import {
IfPermission,
AppIcon,
Expand Down Expand Up @@ -225,7 +227,7 @@ export default class NoteView extends Component {
assigned,
} = this.state.sections;

const noteContentMarkup = { __html: noteData.content };
const noteContentMarkup = { __html: dompurify.sanitize(noteData.content) };

const paneTitle = noteData.title;

Expand Down
10 changes: 9 additions & 1 deletion lib/Notes/NoteViewPage/components/NoteView/tests/interactor.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {
scoped,
clickable,
text,
isPresent
isPresent,
computed,
} from '@bigtest/interactor';

import { AccordionInteractor } from '@folio/stripes-components/lib/Accordion/tests/interactor';
Expand All @@ -12,6 +13,12 @@ import NoValueInteractor from '@folio/stripes-components/lib/NoValue/tests/inter

import ReferredRecordInteractor from '../../../../components/ReferredRecord/tests/interactor';

function markup(selector) {
return computed(function () {
return this.$(selector).innerHTML;
});
}

export default interactor(class NoteViewInteractor {
static defaultScope = '[data-test-note-view]';

Expand All @@ -26,4 +33,5 @@ export default interactor(class NoteViewInteractor {
metaSection = MetaSectionInteractor();
hasEmptyNoteType = isPresent(`[data-test-note-view-note-type] ${NoValueInteractor.defaultScope}`);
hasEmptyNoteTitle = isPresent(`[data-test-note-view-note-title] ${NoValueInteractor.defaultScope}`);
noteContentText = markup('[data-test-note-view-note-details]');
});
52 changes: 52 additions & 0 deletions lib/Notes/NoteViewPage/components/NoteView/tests/note-view-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ const noteData = {
type: 'General note',
};

const noteWithContentData = {
...noteData,
content: '<strong>Message <em>is</em> <u>rendered</u></strong>',
};

const noteWithSusContentData = {
...noteData,
content: '<strong>Message <em>is</em> <u>rendered</u><a href="javascript:alert("failure")">link</a></strong>',
};

const cleanContent = '<strong>Message <em>is</em> <u>rendered</u><a>link</a></strong>';

describe('NoteView', () => {
const noteView = new NoteViewInteractor();

Expand Down Expand Up @@ -112,4 +124,44 @@ describe('NoteView', () => {
expect(noteView.insertedReferredRecord.isPresent).to.be.true;
});
});

describe('rendering NoteView component with content', () => {
setupApplication();

beforeEach(async () => {
await mount(
<NoteView
noteData={noteWithContentData}
entityTypePluralizedTranslationKeys={entityTypePluralizedTranslationKeys}
entityTypeTranslationKeys={entityTypeTranslationKeys}
referredEntityData={referredEntityData}
renderReferredRecord={() => <div data-test-inserted-referred-record>Test</div>}
/>
);
});

it('should display note content', () => {
expect(noteView.noteContentText).to.equal(noteWithContentData.content);
});
});

describe('rendering NoteView component with suspicious content', () => {
setupApplication();

beforeEach(async () => {
await mount(
<NoteView
noteData={noteWithSusContentData}
entityTypePluralizedTranslationKeys={entityTypePluralizedTranslationKeys}
entityTypeTranslationKeys={entityTypeTranslationKeys}
referredEntityData={referredEntityData}
renderReferredRecord={() => <div data-test-inserted-referred-record>Test</div>}
/>
);
});

it('should screen suspicious content for display', () => {
expect(noteView.noteContentText).to.equal(cleanContent);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import dompurify from 'dompurify';
import {
FormattedMessage,
FormattedDate,
Expand Down Expand Up @@ -126,9 +127,9 @@ class NotesList extends React.Component {
</div>
);

const htmlString = isDetailsExpanded[id]
const htmlString = dompurify.sanitize(isDetailsExpanded[id]
? content
: getHTMLSubstring(content, DETAILS_CUTOFF_LENGTH);
: getHTMLSubstring(content, DETAILS_CUTOFF_LENGTH));

const detailsContent = content && (
<div>
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
"dependencies": {
"@rehooks/local-storage": "^2.4.4",
"classnames": "^2.2.6",
"dompurify": "^3.0.9",
"final-form": "^4.18.2",
"final-form-arrays": "^3.0.2",
"lodash": "^4.17.4",
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4872,6 +4872,11 @@ domutils@^1.7.0:
dom-serializer "0"
domelementtype "1"

dompurify@^3.0.9:
version "3.0.9"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.0.9.tgz#b3f362f24b99f53498c75d43ecbd784b0b3ad65e"
integrity sha512-uyb4NDIvQ3hRn6NiC+SIFaP4mJ/MdXlvtunaqK9Bn6dD3RuB/1S/gasEjDHD8eiaqdSael2vBv+hOs7Y+jhYOQ==

domutils@^2.5.2, domutils@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
Expand Down

0 comments on commit 4d56b9e

Please sign in to comment.