diff --git a/packages/rich-text-html-renderer/package-lock.json b/packages/rich-text-html-renderer/package-lock.json index e2f44aff..598d9c88 100644 --- a/packages/rich-text-html-renderer/package-lock.json +++ b/packages/rich-text-html-renderer/package-lock.json @@ -569,6 +569,21 @@ "@types/istanbul-lib-report": "*" } }, + "@types/lodash": { + "version": "4.14.171", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.171.tgz", + "integrity": "sha512-7eQ2xYLLI/LsicL2nejW9Wyko3lcpN6O/z0ZLHrEQsg280zIdCv1t/0m6UtBjUHokCGBQ3gYTbHzDkZ1xOBwwg==", + "dev": true + }, + "@types/lodash.clonedeep": { + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.6.tgz", + "integrity": "sha512-cE1jYr2dEg1wBImvXlNtp0xDoS79rfEdGozQVgliDZj1uERH4k+rmEMTudP9b4VQ8O6nRb5gPqft0QzEQGMQgA==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, "@types/node": { "version": "16.4.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.7.tgz", @@ -2998,6 +3013,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", diff --git a/packages/rich-text-html-renderer/package.json b/packages/rich-text-html-renderer/package.json index 995113b2..c62a157e 100644 --- a/packages/rich-text-html-renderer/package.json +++ b/packages/rich-text-html-renderer/package.json @@ -29,7 +29,9 @@ }, "devDependencies": { "@types/escape-html": "0.0.20", + "@types/lodash.clonedeep": "^4.5.6", "jest": "^24.7.1", + "lodash.clonedeep": "^4.5.0", "rimraf": "^2.6.3", "rollup": "^1.11.0", "rollup-plugin-commonjs": "^9.3.4", diff --git a/packages/rich-text-html-renderer/src/__test__/index.test.ts b/packages/rich-text-html-renderer/src/__test__/index.test.ts index 4663a614..0724c155 100644 --- a/packages/rich-text-html-renderer/src/__test__/index.test.ts +++ b/packages/rich-text-html-renderer/src/__test__/index.test.ts @@ -1,5 +1,5 @@ -import { Document, BLOCKS, MARKS, INLINES } from '@contentful/rich-text-types'; - +import cloneDeep from 'lodash/cloneDeep'; +import { Document, Block, BLOCKS, MARKS, INLINES } from '@contentful/rich-text-types'; import { documentToHtmlString, Options } from '../index'; import { hrDoc, @@ -227,6 +227,23 @@ describe('documentToHtmlString', () => { expect(documentToHtmlString(document)).toEqual(expected); }); + it('renders hyperlink without allowing html injection via `data.uri`', () => { + const document: Document = cloneDeep(hyperlinkDoc); + (document.content[0].content[1] as Block).data.uri = '">no html injection!no html injection!link text.
'; + + expect(documentToHtmlString(document)).toEqual(expected); + }); + + it('renders hyperlink without invalid non-string `data.uri` values', () => { + const document: Document = cloneDeep(hyperlinkDoc); + (document.content[0].content[1] as Block).data.uri = 42; + const expected = 'Some text link text.
'; + + expect(documentToHtmlString(document)).toEqual(expected); + }); + it(`renders asset hyperlink`, () => { const asset = { target: { diff --git a/packages/rich-text-html-renderer/src/index.ts b/packages/rich-text-html-renderer/src/index.ts index 7a244308..b78b6c6d 100644 --- a/packages/rich-text-html-renderer/src/index.ts +++ b/packages/rich-text-html-renderer/src/index.ts @@ -12,6 +12,8 @@ import { } from '@contentful/rich-text-types'; import React from 'react'; +const attributeValue = (value: string) => `"${value.replace(/"/g, '"')}"`; + const defaultNodeRenderers: RenderNode = { [BLOCKS.PARAGRAPH]: (node, next) => `${next(node.content)}
`, [BLOCKS.HEADING_1]: (node, next) => `