Skip to content

Commit b6f962e

Browse files
authoredFeb 17, 2025··
Merge pull request #104 from contentstack/development
Development
2 parents 8795dee + a2d0cb6 commit b6f962e

File tree

14 files changed

+456
-457
lines changed

14 files changed

+456
-457
lines changed
 

‎src/main/java/com/contentstack/utils/node/NodeToHTML.java

+21-12
Original file line numberDiff line numberDiff line change
@@ -29,35 +29,44 @@ private NodeToHTML() {
2929
*/
3030
public static String textNodeToHTML(JSONObject nodeText, Option renderOption) {
3131
String text = nodeText.optString("text");
32-
text = text.replace("\n", "<br />");
32+
//Sanitization of text
33+
String cleanedText = escapeTextNodes(text)
34+
.replace("\n", "<br />")
35+
.replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;");
36+
3337
if (nodeText.has("superscript")) {
34-
text = renderOption.renderMark(MarkType.SUPERSCRIPT, text);
38+
cleanedText = renderOption.renderMark(MarkType.SUPERSCRIPT, cleanedText);
3539
}
3640
if (nodeText.has("subscript")) {
37-
text = renderOption.renderMark(MarkType.SUBSCRIPT, text);
41+
cleanedText = renderOption.renderMark(MarkType.SUBSCRIPT, cleanedText);
3842
}
3943
if (nodeText.has("inlineCode")) {
40-
text = renderOption.renderMark(MarkType.INLINECODE, text);
44+
cleanedText = renderOption.renderMark(MarkType.INLINECODE, cleanedText);
4145
}
4246
if (nodeText.has("strikethrough")) {
43-
text = renderOption.renderMark(MarkType.STRIKETHROUGH, text);
47+
cleanedText = renderOption.renderMark(MarkType.STRIKETHROUGH, cleanedText);
4448
}
4549
if (nodeText.has("underline")) {
46-
text = renderOption.renderMark(MarkType.UNDERLINE, text);
50+
cleanedText = renderOption.renderMark(MarkType.UNDERLINE, cleanedText);
4751
}
4852
if (nodeText.has("italic")) {
49-
text = renderOption.renderMark(MarkType.ITALIC, text);
53+
cleanedText = renderOption.renderMark(MarkType.ITALIC, cleanedText);
5054
}
5155
if (nodeText.has("bold")) {
52-
text = renderOption.renderMark(MarkType.BOLD, text);
56+
cleanedText = renderOption.renderMark(MarkType.BOLD, cleanedText);
5357
}
5458
if (nodeText.has("break")) {
55-
if (!text.contains("<br />")) {
56-
text = renderOption.renderMark(MarkType.BREAK, text);
59+
if (!cleanedText.contains("<br />")) {
60+
cleanedText = renderOption.renderMark(MarkType.BREAK, cleanedText);
5761
}
58-
// text = renderOption.renderMark(MarkType.BREAK, text);
62+
// cleanedText = renderOption.renderMark(MarkType.BREAK, cleanedText);
5963
}
60-
return text;
64+
return cleanedText;
6165
}
6266

67+
private static String escapeTextNodes(String input) {
68+
return input.replace("&", "&amp;")
69+
.replace("<", "&lt;")
70+
.replace(">", "&gt;");
71+
}
6372
}

‎src/main/java/com/contentstack/utils/render/DefaultOption.java

+29-41
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
import com.contentstack.utils.node.MarkType;
77
import org.apache.commons.text.StringEscapeUtils;
88
import org.json.JSONObject;
9-
import org.jsoup.Jsoup;
10-
import org.jsoup.nodes.Document;
119

1210
import java.util.*;
1311

@@ -104,79 +102,77 @@ private String escapeInjectHtml(JSONObject nodeObj, String nodeType) {
104102
public String renderNode(String nodeType, JSONObject nodeObject, NodeCallback callback) {
105103
String strAttrs = strAttrs(nodeObject);
106104
String children = callback.renderChildren(nodeObject.optJSONArray("children"));
107-
// Jsoup sanitization
108-
Document sanitizedChildren = Jsoup.parse(children);
109-
String cleanChildren = sanitizedChildren.body().html();
105+
110106
switch (nodeType) {
111107
case "p":
112-
return "<p" + strAttrs + ">" + cleanChildren + "</p>";
108+
return "<p" + strAttrs + ">" + children + "</p>";
113109
case "a":
114-
return "<a" + strAttrs + " href=\"" + escapeInjectHtml(nodeObject, "href") + "\">" + cleanChildren + "</a>";
110+
return "<a" + strAttrs + " href=\"" + escapeInjectHtml(nodeObject, "href") + "\">" + children + "</a>";
115111
case "img":
116112
String assetLink = getNodeStr(nodeObject, "asset-link");
117113
if (!assetLink.isEmpty()) {
118114
JSONObject attrs = nodeObject.optJSONObject("attrs");
119115
if (attrs.has("link")) {
120-
return "<a href=\"" + escapeInjectHtml(nodeObject, "link") + "\" >" + "<img" + strAttrs + " src=\"" + escapeInjectHtml(nodeObject, "asset-link") + "\" />" + cleanChildren + "</a>";
116+
return "<a href=\"" + escapeInjectHtml(nodeObject, "link") + "\" >" + "<img" + strAttrs + " src=\"" + escapeInjectHtml(nodeObject, "asset-link") + "\" />" + children + "</a>";
121117
}
122-
return "<img" + strAttrs + " src=\"" + escapeInjectHtml(nodeObject, "asset-link") + "\" />" + cleanChildren;
118+
return "<img" + strAttrs + " src=\"" + escapeInjectHtml(nodeObject, "asset-link") + "\" />" + children;
123119
}
124-
return "<img" + strAttrs + " src=\"" + escapeInjectHtml(nodeObject, "src") + "\" />" + cleanChildren;
120+
return "<img" + strAttrs + " src=\"" + escapeInjectHtml(nodeObject, "src") + "\" />" + children;
125121
case "embed":
126-
return "<iframe" + strAttrs + " src=\"" + escapeInjectHtml(nodeObject, "src") + "\"" + cleanChildren + "</iframe>";
122+
return "<iframe" + strAttrs + " src=\"" + escapeInjectHtml(nodeObject, "src") + "\"" + children + "</iframe>";
127123
case "h1":
128-
return "<h1" + strAttrs + ">" + cleanChildren + "</h1>";
124+
return "<h1" + strAttrs + ">" + children + "</h1>";
129125
case "h2":
130-
return "<h2" + strAttrs + ">" + cleanChildren + "</h2>";
126+
return "<h2" + strAttrs + ">" + children + "</h2>";
131127
case "h3":
132-
return "<h3" + strAttrs + ">" + cleanChildren + "</h3>";
128+
return "<h3" + strAttrs + ">" + children + "</h3>";
133129
case "h4":
134-
return "<h4" + strAttrs + ">" + cleanChildren + "</h4>";
130+
return "<h4" + strAttrs + ">" + children + "</h4>";
135131
case "h5":
136-
return "<h5" + strAttrs + ">" + cleanChildren + "</h5>";
132+
return "<h5" + strAttrs + ">" + children + "</h5>";
137133
case "h6":
138-
return "<h6" + strAttrs + ">" + cleanChildren + "</h6>";
134+
return "<h6" + strAttrs + ">" + children + "</h6>";
139135
case "ol":
140-
return "<ol" + strAttrs + ">" + cleanChildren + "</ol>";
136+
return "<ol" + strAttrs + ">" + children + "</ol>";
141137
case "ul":
142-
return "<ul" + strAttrs + ">" + cleanChildren + "</ul>";
138+
return "<ul" + strAttrs + ">" + children + "</ul>";
143139
case "li":
144-
return "<li" + strAttrs + ">" + cleanChildren + "</li>";
140+
return "<li" + strAttrs + ">" + children + "</li>";
145141
case "hr":
146142
return "<hr" + strAttrs + " />";
147143
case "table":
148-
return "<table " + strAttrs + ">" + cleanChildren + "</table>";
144+
return "<table " + strAttrs + ">" + children + "</table>";
149145
case "thead":
150-
return "<thead " + strAttrs + ">" + cleanChildren + "</thead>";
146+
return "<thead " + strAttrs + ">" + children + "</thead>";
151147
case "tbody":
152-
return "<tbody" + strAttrs + ">" + cleanChildren + "</tbody>";
148+
return "<tbody" + strAttrs + ">" + children + "</tbody>";
153149
case "tfoot":
154-
return "<tfoot" + strAttrs + ">" + cleanChildren + "</tfoot>";
150+
return "<tfoot" + strAttrs + ">" + children + "</tfoot>";
155151
case "tr":
156-
return "<tr" + strAttrs + ">" + cleanChildren + "</tr>";
152+
return "<tr" + strAttrs + ">" + children + "</tr>";
157153
case "th":{
158154
if (nodeObject.has("attrs") && nodeObject.optJSONObject("attrs").has("void") &&
159155
nodeObject.optJSONObject("attrs").optBoolean("void")) {
160156
return "";
161157
}else{
162-
return "<th" + strAttrs + ">" + cleanChildren + "</th>";}}
158+
return "<th" + strAttrs + ">" + children + "</th>";}}
163159
case "td":{
164160
if (nodeObject.has("attrs") && nodeObject.optJSONObject("attrs").has("void") &&
165161
nodeObject.optJSONObject("attrs").optBoolean("void")) {
166162
return "";
167163
}else{
168-
return "<td" + strAttrs + ">" + cleanChildren + "</td>";}}
164+
return "<td" + strAttrs + ">" + children + "</td>";}}
169165

170166
case "blockquote":
171-
return "<blockquote" + strAttrs + ">" + cleanChildren + "</blockquote>";
167+
return "<blockquote" + strAttrs + ">" + children + "</blockquote>";
172168
case "code":
173-
return "<code" + strAttrs + ">" + cleanChildren + "</code>";
169+
return "<code" + strAttrs + ">" + children + "</code>";
174170
case "reference":
175171
return "";
176172
case "fragment":
177-
return "<fragment" + strAttrs + ">" + cleanChildren + "</fragment>";
173+
return "<fragment" + strAttrs + ">" + children + "</fragment>";
178174
default:
179-
return cleanChildren;
175+
return children;
180176
}
181177
}
182178

@@ -197,16 +193,8 @@ String strAttrs(JSONObject nodeObject) {
197193
for (String key : attrsObject.keySet()) {
198194
Object objValue = attrsObject.opt(key);
199195
String value = objValue.toString();
200-
201-
StringBuilder escapedValue = new StringBuilder();
202-
for (char ch : value.toCharArray()) {
203-
if (ch == '&' || ch == '<' || ch == '>' || ch == '"' || ch == '\'') {
204-
escapedValue.append("&#").append((int) ch).append(';');
205-
} else {
206-
escapedValue.append(ch);
207-
}
208-
}
209-
value = escapedValue.toString();
196+
// Escape HTML entities using StringEscapeUtils
197+
value = StringEscapeUtils.escapeHtml4(value);
210198
// If style is available, do styling calculations
211199
if (Objects.equals(key, "style")) {
212200
String resultStyle = stringifyStyles(attrsObject.optJSONObject("style"));

0 commit comments

Comments
 (0)