Skip to content

Commit ca4b919

Browse files
Merge pull request #141 from contentstack/staging
DX | 17-02-2025 | Hotfix
2 parents 8292db8 + d880132 commit ca4b919

10 files changed

+95
-38
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## [1.3.18](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.3.17) (2025-02-17)
4+
- Fix: Added fix for html injection
5+
36
## [1.3.17](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.3.17) (2025-02-11)
47
- Enh: updateAssetURLForGQL update for multilpe entries
58
- Fix: Added support of br tag (\n) after just enter

__test__/json-to-html.test.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ import {
3333
orderListJson2,
3434
testJsonRte,
3535
testJsonAsset,
36-
embeddedAssetAsLinkJsonEntry} from './mock/json-element-mock'
36+
embeddedAssetAsLinkJsonEntry,
37+
escapeJsonHtml } from './mock/json-element-mock'
3738
import {
3839
blockquoteHtml,
3940
codeHtml,
@@ -60,7 +61,8 @@ import {
6061
styleObjHtml,
6162
referenceObjHtml,
6263
referenceObjHtmlBlock,
63-
imagetags} from './mock/json-element-mock-result'
64+
imagetags,
65+
escapeHtml } from './mock/json-element-mock-result'
6466
describe('Node parser paragraph content', () => {
6567
it('Should accept proper values', done => {
6668
const entry = { uid: 'uid'}
@@ -122,6 +124,15 @@ describe('Node parser paragraph content', () => {
122124
expect(entry.rich_text_editor).toEqual([paragraphHtml])
123125
done()
124126
})
127+
128+
it('Should render Json To html', done => {
129+
const entry = {...escapeJsonHtml}
130+
131+
jsonToHTML({entry, paths: ['rich_text_editor']})
132+
133+
expect(entry.rich_text_editor).toEqual(escapeHtml)
134+
done()
135+
})
125136
})
126137

127138

__test__/mock/gql-asset-url-update-mock.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -264,21 +264,13 @@ export const gqlResponseForAssetUpdateMultipleEntries = {
264264
"title": "merry-marketplace.png",
265265
"url": "actual_asset_url.png",
266266
"content_type": "image/png",
267-
"description": null,
267+
"description": "null",
268268
"file_size": 273858,
269269
"filename": "merry-marketplace.png",
270-
"permanent_url": "Permanent URL Not Defined!"
271-
}
272-
},
273-
{
274-
"node": {
275-
"title": "Screenshot.png",
276-
"url": "https://azure-na-images.contentstack.com/v3/assets/folder_uid/asset_uid_2/folder_uid_4/Screenshot_2024-12-09_at_7.28.28_PM.png?branch=test2",
277-
"content_type": "image/png",
278-
"description": "",
279-
"file_size": 287954,
280-
"filename": "Screenshot_2024-12-09_at_7.28.28_PM.png",
281-
"permanent_url": "Permanent URL Not Defined!"
270+
"permanent_url": "Permanent URL Not Defined!",
271+
"system" : {
272+
"uid": "asset_uid_1"
273+
}
282274
}
283275
},
284276
{
@@ -289,7 +281,10 @@ export const gqlResponseForAssetUpdateMultipleEntries = {
289281
"description": "",
290282
"file_size": 1050317,
291283
"filename": "Aadhaar.pdf",
292-
"permanent_url": "Permanent URL Not Defined!"
284+
"permanent_url": "Permanent URL Not Defined!",
285+
"system" : {
286+
"uid": "asset_uid_2"
287+
}
293288
}
294289
}
295290
]

__test__/mock/json-element-mock-result.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ const classAndIdAttrsHtml = "<a class=\"class_a\" id=\"id_p\" href=\"LINK.com\">
2323
const styleObjHtml = "<h1 style=\"text-align:justify;\">heading1</h1><h2 style=\"text-align:left;\">heading2</h2><h3 style=\"text-align:right;\">heading3</h3><h4 style=\"text-align:justify;\">heading4</h4><h5 style=\"text-align:justify;\">heading5</h5><h6 style=\"text-align:justify;\">heading6</h6>"
2424
const referenceObjHtml = "<p><a class=\"embedded-entry redactor-component block-entry\" href=\"/test\" target=\"_self\">Embed entry as a link</a></p><p><a class=\"embedded-entry redactor-component block-entry\" href=\"/entry-3\" target=\"_blank\">Open entry as a link in new tab</a></p><p><a class=\"embedded-entry redactor-component block-entry\" href=\"/entry-2\" target=\"_self\">Bold entry</a></p><p><a class=\"embedded-entry redactor-component block-entry\" href=\"/entry-4\" target=\"_blank\"><strong>Bold entry open in new tab</strong></a></p>"
2525
const referenceObjHtmlBlock = "<p><a class=\"embedded-entry redactor-component block-entry\" href=\"/Test\" target=\"_self\">Embed entry as a link</a></p><p><a class=\"embedded-entry redactor-component block-entry\" href=\"undefined\" target=\"_blank\">Embed entry as a link open in new tab</a></p><ul><li><a class=\"embedded-entry redactor-component block-entry\" href=\"undefined\" target=\"_self\">Entry as a link</a></li><li><a class=\"embedded-entry redactor-component block-entry\" href=\"undefined\" target=\"_blank\">Open entry as a link in new tab</a></li><li><a class=\"embedded-entry redactor-component block-entry\" href=\"undefined\" target=\"_self\"><strong><u>Entry as a link bold</u></strong></a></li><li><a class=\"embedded-entry redactor-component block-entry\" href=\"khjgf\" target=\"_blank\"><strong><u>Open bold entry as a link in new tab </u></strong></a></li><li><a href=\"https://\" target=\"_self\"><strong><u>Link URL</u></strong></a></li><li><a href=\"https://\" target=\"_blank\"><strong><u>Open link in new tab</u></strong></a></li></ul>"
26-
2726
const imagetags = "<figure style=\"text-align:right;max-width:137px;float:right;width:137px;max-height:257px;height:257px;\"><a href=\"https://batman.com\" target=\"_blank\"><img asset_uid=\"asset-UID\" class=\"embedded-asset\" src=\"https://images.contentstack.io/v3/assets/api-key/asset-UID/random-uid/batman.png\" alt=\"batman\" target=\"_blank\" style=\"text-align:right;max-width:137px;float:right;width:137px;max-height:257px;height:257px;\" /></a><figcaption>The Batman</figcaption></figure>"
27+
const escapeHtml = "<p>&lt;p&gt;Welcome to Contentstack! &lt;script&gt;console.log(/\"Hello from Contentstack!/\");&lt;/script&gt; Explore our platform to create, manage, and publish content seamlessly.&lt;/p&gt;</p>"
2828

2929
export {
3030
h1Html,
@@ -53,5 +53,5 @@ export {
5353
referenceObjHtmlBlock,
5454
imagetags,
5555
paragraphHtmlWithNewLine,
56-
56+
escapeHtml
5757
}

__test__/mock/json-element-mock.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2394,6 +2394,33 @@ const testJsonAsset={
23942394
"_version": 22
23952395
}
23962396
}
2397+
2398+
const escapeJsonHtml = {
2399+
title: 'entry and assets',
2400+
url: '/entry-and-assets',
2401+
rich_text_editor: {
2402+
uid: "uid",
2403+
_version: 13,
2404+
attrs: {},
2405+
children: [
2406+
{
2407+
type: "p",
2408+
attrs: {},
2409+
uid: "0a1b5676aa510e5a",
2410+
children: [
2411+
{
2412+
text: '<p>Welcome to Contentstack! <script>console.log(/"Hello from Contentstack!/");</script> Explore our platform to create, manage, and publish content seamlessly.</p>'
2413+
}
2414+
]
2415+
}
2416+
],
2417+
type: "doc"
2418+
},
2419+
locale: 'en-us',
2420+
_in_progress: false,
2421+
uid: 'asset_uid_10',
2422+
}
2423+
23972424
export {
23982425
h1Json,
23992426
h2Json,
@@ -2432,5 +2459,6 @@ export {
24322459
orderListJson2,
24332460
testJsonRte,
24342461
testJsonAsset,
2435-
paragraphEntryWithNewline
2462+
paragraphEntryWithNewline,
2463+
escapeJsonHtml
24362464
}

__test__/updateAssetURLForGQL.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { gqlResponseForAssetUpdate, gqlResponseForAssetUpdateWithoutSystemUid, g
33

44
describe('updateAssetURLForGQL test', () => {
55

6-
it.skip('should update the asset URL in the GQL response when proper response is passed', done => {
6+
it('should update the asset URL in the GQL response when proper response is passed', done => {
77
const testResponse = { ...gqlResponseForAssetUpdate };
88
updateAssetURLForGQL(testResponse);
99

@@ -15,19 +15,19 @@ describe('updateAssetURLForGQL test', () => {
1515
done();
1616
});
1717

18-
it.skip('should update the asset URL in the GQL response when proper response is passed', done => {
18+
it('should update the asset URL in the GQL response with multiple entries when proper response is passed', done => {
1919
const testResponse = { ...gqlResponseForAssetUpdateMultipleEntries };
2020
updateAssetURLForGQL(testResponse);
2121

2222
const rteField = testResponse.data.page_json_rte.items[0].body_new[0].body.body_12;
2323
const assetLink = rteField.json.children[0].attrs['asset-link'];
2424
const expectedUrl = rteField.embedded_itemsConnection.edges[0].node.url;
25-
25+
2626
expect(assetLink).toBe(expectedUrl);
2727
done();
2828
});
2929

30-
it.skip('should throw error when system.uid is not present', done => {
30+
it('should throw error when system.uid is not present', done => {
3131
jest.spyOn(console, 'error').mockImplementation(() => {});
3232

3333
const testResponse = { ...gqlResponseForAssetUpdateWithoutSystemUid };

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@contentstack/utils",
3-
"version": "1.3.17",
3+
"version": "1.3.18",
44
"description": "Contentstack utilities for Javascript",
55
"main": "dist/index.es.js",
66
"types": "dist/types/index.d.ts",

src/helper/enumerate-entries.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export function enumerateContents(
4242
}
4343

4444
export function textNodeToHTML(node: TextNode, renderOption: RenderOption): string {
45-
let text = node.text;
45+
let text = escapeHtml(node.text);
4646
if (node.classname || node.id) {
4747
text = (renderOption[MarkType.CLASSNAME_OR_ID] as RenderMark)(text, node.classname, node.id);
4848
}
@@ -158,3 +158,10 @@ function nodeToHTML(
158158
}
159159
}
160160
}
161+
162+
function escapeHtml(text: string): string {
163+
return text
164+
.replace(/&/g, '&amp;')
165+
.replace(/</g, '&lt;')
166+
.replace(/>/g, '&gt;')
167+
}

src/updateAssetURLForGQL.ts

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,34 @@ export function updateAssetURLForGQL(gqlResponse:any) {
2020
function processEntry(entry:any) {
2121
for (let field in entry) {
2222
const fieldData = entry[field];
23-
const rteField = findRTEField(fieldData)
24-
const edges = rteField?.embedded_itemsConnection?.edges;
25-
edges.forEach((edge:any) => {
26-
const node = edge.node;
27-
if (node?.url && node?.filename) {
28-
29-
if (!node?.system?.uid) throw new Error('Asset UID not found in the response');
30-
31-
const correspondingAsset = rteField?.json?.children?.find((child:any) => child.attrs['asset-uid'] === node.system.uid);
32-
correspondingAsset.attrs['asset-link'] = node.url;
33-
}
23+
if (fieldData instanceof Array) {
24+
fieldData.forEach((data:any) => {
25+
findRTEFieldAndUpdateURL(data);
3426
});
27+
} else if (fieldData && typeof fieldData === 'object') {
28+
findRTEFieldAndUpdateURL(fieldData);
29+
}
3530
}
3631
}
3732

33+
function findRTEFieldAndUpdateURL(fieldData:any) {
34+
const rteField = findRTEField(fieldData);
35+
36+
if (!rteField) return;
37+
38+
const edges = rteField?.embedded_itemsConnection?.edges;
39+
edges.forEach((edge:any) => {
40+
const node = edge.node;
41+
if (node?.url && node?.filename) {
42+
43+
if (!node?.system?.uid) throw new Error('Asset UID not found in the response');
44+
45+
const correspondingAsset = rteField?.json?.children?.find((child:any) => child.attrs['asset-uid'] === node.system.uid);
46+
correspondingAsset.attrs['asset-link'] = node.url;
47+
}
48+
});
49+
}
50+
3851
function findRTEField(fieldData: any): any {
3952
if (fieldData && fieldData.embedded_itemsConnection) {
4053
return fieldData;

0 commit comments

Comments
 (0)