From 2e8970f386eec1271785cf07445501d0cb0350ee Mon Sep 17 00:00:00 2001 From: sunil-lakshman <104969541+sunil-lakshman@users.noreply.github.com> Date: Sat, 8 Feb 2025 11:34:10 +0530 Subject: [PATCH 1/4] chore: Added support of \n after just enter (#133) * chore: Added support of \n after just enter * chore: Updated changelog --- CHANGELOG.md | 1 + __test__/json-to-html.test.ts | 9 +++++ __test__/mock/json-element-mock-result.ts | 2 ++ __test__/mock/json-element-mock.ts | 41 ++++++++++++++++++++++- src/helper/sanitize.ts | 4 +++ 5 files changed, 56 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5458fb..4bd1d00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [1.3.17](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.3.17) (2025-02-11) - Enh: updateAssetURLForGQL update for multilpe entries + - Fix: Added support of br tag (\n) after just enter ## [1.3.16](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.3.16) (2025-01-27) - Enh: Added support for colgroup and col tags inside table tag diff --git a/__test__/json-to-html.test.ts b/__test__/json-to-html.test.ts index f72fd4d..720feac 100644 --- a/__test__/json-to-html.test.ts +++ b/__test__/json-to-html.test.ts @@ -17,6 +17,7 @@ import { linkInPJsonUrl, orderListJson, paragraphEntry, + paragraphEntryWithNewline, paragraphJsonArrayEntry, plainTextJson, styleinPJson, @@ -47,6 +48,7 @@ import { linkInPURLHtml, orderListHtml, paragraphHtml, + paragraphHtmlWithNewLine, plainTextHtml, styleinPHtml, tableHtml, @@ -87,6 +89,13 @@ describe('Node parser paragraph content', () => { done() }) + it('Should render Json To html with newline after single enter', done => { + const entry = {...paragraphEntryWithNewline} + jsonToHTML({entry, paths: ['rich_text_editor']}) + expect(entry.rich_text_editor).toEqual(paragraphHtmlWithNewLine) + done() + }) + it('Should render Json To html for Array of Entries', done => { const entry = {...paragraphEntry} diff --git a/__test__/mock/json-element-mock-result.ts b/__test__/mock/json-element-mock-result.ts index a4fab81..7b1b349 100644 --- a/__test__/mock/json-element-mock-result.ts +++ b/__test__/mock/json-element-mock-result.ts @@ -1,5 +1,6 @@ const plainTextHtml = "Aliquam sit amet libero dapibus, eleifend ligula at, varius justoLorem ipsumdolor sit amet
consectetur adipiscing elit.
Sed condimentum iaculis magna in vehicula. Vestibulum vitae convallis lacus. " const paragraphHtml = "

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed condimentum iaculis magna in vehicula. Vestibulum vitae convallis lacus. Praesent a diam iaculis turpis rhoncus faucibus. Aliquam sed pulvinar sem.

" +const paragraphHtmlWithNewLine = "

Ritesh test

Shift enter
single enter

" const h1Html = "

Lorem ipsum dolor sit amet.

" const h2Html = "

Vestibulum a ligula eget massa sagittis aliquam sit amet quis tortor.

" const h3Html = "

Mauris venenatis dui id massa sollicitudin, non bibendum nunc dictum.

" @@ -51,5 +52,6 @@ export { referenceObjHtml, referenceObjHtmlBlock, imagetags, + paragraphHtmlWithNewLine, } \ No newline at end of file diff --git a/__test__/mock/json-element-mock.ts b/__test__/mock/json-element-mock.ts index c5fe596..1863c3f 100644 --- a/__test__/mock/json-element-mock.ts +++ b/__test__/mock/json-element-mock.ts @@ -659,6 +659,35 @@ const paragraphJson = { type: "doc" } +const paragraphJsonWithNewline = { + "type": "doc", + "attrs": {}, + "uid": "abcdefgh123456", + "children": [ + { + "type": "p", + "uid": "abcdefgh123456", + "attrs": {}, + "children": [ + { + "text": "Ritesh test" + } + ] + }, + { + "uid": "abcdefgh123456", + "type": "p", + "children": [ + { + "text": "Shift enter\nsingle enter" + } + ], + "attrs": {} + } + ], + "_version": 26 +} + const blockquoteJson = { uid: "06084d7fd", _version: 13, @@ -1128,6 +1157,15 @@ const paragraphEntry = { uid: 'asset_uid_10', } +const paragraphEntryWithNewline = { + title: 'entry and assets', + url: '/entry-and-assets', + rich_text_editor: {...paragraphJsonWithNewline}, + locale: 'en-us', + _in_progress: false, + uid: 'asset_uid_10', +} + const paragraphJsonArrayEntry = { title: 'entry and assets', url: '/entry-and-assets', @@ -2393,5 +2431,6 @@ export { unorderListJson2, orderListJson2, testJsonRte, - testJsonAsset + testJsonAsset, + paragraphEntryWithNewline } \ No newline at end of file diff --git a/src/helper/sanitize.ts b/src/helper/sanitize.ts index b2d66ca..48539aa 100644 --- a/src/helper/sanitize.ts +++ b/src/helper/sanitize.ts @@ -3,6 +3,10 @@ type AllowedTags = 'p' | 'a' | 'strong' | 'em' | 'ul' | 'ol' | 'li' | 'h1' | 'h2 type AllowedAttributes = 'href' | 'title' | 'target' | 'alt' | 'src' | 'class' | 'id' | 'style' | 'colspan' | 'rowspan' | 'content-type-uid' | 'data-sys-asset-uid' | 'sys-style-type' | 'data-type' | 'data-width' | 'data-rows' | 'data-cols'; export function sanitizeHTML(input: string, allowedTags: AllowedTags[] = ['p', 'a', 'strong', 'em', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'sub', 'u', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'span', 'fragment', 'sup', 'strike', 'br', 'img', 'colgroup', 'col', 'div'], allowedAttributes: AllowedAttributes[] = ['href', 'title', 'target', 'alt', 'src', 'class', 'id', 'style', 'colspan', 'rowspan', 'content-type-uid', 'data-sys-asset-uid', 'sys-style-type', 'data-type', 'data-width', 'data-rows', 'data-cols']): string { + + // Replace newline characters with
before processing the HTML tags + input = input.replace(/\n/g, '
'); + // Regular expression to find and remove all HTML tags except the allowed ones const sanitized = input.replace(/<\/?([a-z][a-z0-9]*)\b[^<>]*>/gi, (match, tag) => { return allowedTags.includes(tag.toLowerCase()) ? match : ''; From 38cca9fe31d928221953a1c91525e827e479954e Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Wed, 12 Feb 2025 12:28:55 +0530 Subject: [PATCH 2/4] fix: fix for html injection --- src/helper/enumerate-entries.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/helper/enumerate-entries.ts b/src/helper/enumerate-entries.ts index 5e3fd90..c23e5b6 100644 --- a/src/helper/enumerate-entries.ts +++ b/src/helper/enumerate-entries.ts @@ -42,7 +42,7 @@ export function enumerateContents( } export function textNodeToHTML(node: TextNode, renderOption: RenderOption): string { - let text = node.text; + let text = escapeHtml(node.text); if (node.classname || node.id) { text = (renderOption[MarkType.CLASSNAME_OR_ID] as RenderMark)(text, node.classname, node.id); } @@ -158,3 +158,10 @@ function nodeToHTML( } } } + +function escapeHtml(text: string): string { + return text + .replace(/&/g, '&') + .replace(//g, '>') +} \ No newline at end of file From 665b422eb664f3155179f4274dea4a270f0d2810 Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Wed, 12 Feb 2025 12:31:06 +0530 Subject: [PATCH 3/4] test: test for html injection fix --- __test__/json-to-html.test.ts | 15 ++++++++++-- __test__/mock/json-element-mock-result.ts | 4 +-- __test__/mock/json-element-mock.ts | 30 ++++++++++++++++++++++- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/__test__/json-to-html.test.ts b/__test__/json-to-html.test.ts index 720feac..de20842 100644 --- a/__test__/json-to-html.test.ts +++ b/__test__/json-to-html.test.ts @@ -33,7 +33,8 @@ import { orderListJson2, testJsonRte, testJsonAsset, - embeddedAssetAsLinkJsonEntry} from './mock/json-element-mock' + embeddedAssetAsLinkJsonEntry, + escapeJsonHtml } from './mock/json-element-mock' import { blockquoteHtml, codeHtml, @@ -60,7 +61,8 @@ import { styleObjHtml, referenceObjHtml, referenceObjHtmlBlock, - imagetags} from './mock/json-element-mock-result' + imagetags, + escapeHtml } from './mock/json-element-mock-result' describe('Node parser paragraph content', () => { it('Should accept proper values', done => { const entry = { uid: 'uid'} @@ -122,6 +124,15 @@ describe('Node parser paragraph content', () => { expect(entry.rich_text_editor).toEqual([paragraphHtml]) done() }) + + it('Should render Json To html', done => { + const entry = {...escapeJsonHtml} + + jsonToHTML({entry, paths: ['rich_text_editor']}) + + expect(entry.rich_text_editor).toEqual(escapeHtml) + done() + }) }) diff --git a/__test__/mock/json-element-mock-result.ts b/__test__/mock/json-element-mock-result.ts index 7b1b349..800d991 100644 --- a/__test__/mock/json-element-mock-result.ts +++ b/__test__/mock/json-element-mock-result.ts @@ -23,8 +23,8 @@ const classAndIdAttrsHtml = " const styleObjHtml = "

heading1

heading2

heading3

heading4

heading5
heading6
" const referenceObjHtml = "

Embed entry as a link

Open entry as a link in new tab

Bold entry

Bold entry open in new tab

" const referenceObjHtmlBlock = "

Embed entry as a link

Embed entry as a link open in new tab

" - const imagetags = "
\"batman\"
The Batman
" +const escapeHtml = "

<p>Welcome to Contentstack! <script>console.log(/\"Hello from Contentstack!/\");</script> Explore our platform to create, manage, and publish content seamlessly.</p>

" export { h1Html, @@ -53,5 +53,5 @@ export { referenceObjHtmlBlock, imagetags, paragraphHtmlWithNewLine, - + escapeHtml } \ No newline at end of file diff --git a/__test__/mock/json-element-mock.ts b/__test__/mock/json-element-mock.ts index 1863c3f..463d28e 100644 --- a/__test__/mock/json-element-mock.ts +++ b/__test__/mock/json-element-mock.ts @@ -2394,6 +2394,33 @@ const testJsonAsset={ "_version": 22 } } + +const escapeJsonHtml = { + title: 'entry and assets', + url: '/entry-and-assets', + rich_text_editor: { + uid: "uid", + _version: 13, + attrs: {}, + children: [ + { + type: "p", + attrs: {}, + uid: "0a1b5676aa510e5a", + children: [ + { + text: '

Welcome to Contentstack! Explore our platform to create, manage, and publish content seamlessly.

' + } + ] + } + ], + type: "doc" +}, + locale: 'en-us', + _in_progress: false, + uid: 'asset_uid_10', +} + export { h1Json, h2Json, @@ -2432,5 +2459,6 @@ export { orderListJson2, testJsonRte, testJsonAsset, - paragraphEntryWithNewline + paragraphEntryWithNewline, + escapeJsonHtml } \ No newline at end of file From 031e7cd804bc509d25edad77dcb37ccf36f26d31 Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Wed, 12 Feb 2025 12:31:59 +0530 Subject: [PATCH 4/4] chore: update version to 1.3.18 and document html injection fix in changelog --- CHANGELOG.md | 3 +++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bd1d00..0449694 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## [1.3.18](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.3.17) (2025-02-17) + - Fix: Added fix for html injection + ## [1.3.17](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.3.17) (2025-02-11) - Enh: updateAssetURLForGQL update for multilpe entries - Fix: Added support of br tag (\n) after just enter diff --git a/package-lock.json b/package-lock.json index c4d63a0..af29222 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@contentstack/utils", - "version": "1.3.17", + "version": "1.3.18", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@contentstack/utils", - "version": "1.3.17", + "version": "1.3.18", "license": "MIT", "devDependencies": { "@babel/preset-env": "^7.26.0", diff --git a/package.json b/package.json index 5479b66..7dfc8b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@contentstack/utils", - "version": "1.3.17", + "version": "1.3.18", "description": "Contentstack utilities for Javascript", "main": "dist/index.es.js", "types": "dist/types/index.d.ts",