Skip to content

feat: handle invalid attr key-values #76

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,35 @@ To help the JSON RTE Serializer recognize and process additional tags that are c

### Convert JSON to HTML

#### HTML Attribute Name and Value Sanitization


This project ensures that HTML attributes are properly validated and sanitized according to the W3C HTML specification. It validates attribute names based on the HTML standards and sanitizes attribute values to ensure correct rendering and security, particularly against cross-site scripting (XSS) vulnerabilities.

#### Attribute Name Guidelines

All HTML attribute names must conform to the [W3C HTML specification](https://www.w3.org/TR/2012/WD-html-markup-20120329/syntax.html#attribute-name). These guidelines specify the following rules:

- **Printable ASCII Characters:** Attribute names must consist only of printable ASCII characters.
- **Case-Insensitive:** Attribute names are case-insensitive, but lowercase is preferred for consistency.
- **No Special Characters:** Attribute names cannot contain spaces or special characters such as `=`, `>`, `<`, `"`, etc.
- **Allowed Attributes:** Attributes such as `xmlns`, `aria-*`, `data-*`, and others defined by HTML5 standards are allowed and must follow specific rules.

##### Important Note:
If an attribute name does not conform to these rules, the attribute will be **dropped** from the element.

#### Attribute Value Guidelines

The values of HTML attributes are sanitized to ensure proper rendering and to mitigate security risks, such as Cross-Site Scripting (XSS). This sanitization process involves replacing HTML entities (like `&lt;`, `&gt;`, `&amp;`, etc.) with their corresponding characters and removing any invalid or unsafe characters.

Here are some common HTML entities and their replacements:

- `&lt;` → `<`
- `&gt;` → `>`
- `&amp;` → `&`


<hr>
You can pass the `allowNonStandardTags: true` parameter within the `jsonToHtml` method to allow the JSON RTE Serializer tool to recognize standard HTML tags or element types and convert them into JSON format.

You can use the following customized JSON RTE Serializer code to convert your JSON RTE field data into HTML format.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@contentstack/json-rte-serializer",
"version": "2.0.13",
"version": "2.1.0",
"description": "This Package converts Html Document to Json and vice-versa.",
"main": "lib/index.js",
"module": "lib/index.mjs",
Expand Down
5 changes: 4 additions & 1 deletion src/toRedactor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import kebbab from 'lodash.kebabcase'
import isEmpty from 'lodash.isempty'
import {IJsonToHtmlElementTags, IJsonToHtmlOptions, IJsonToHtmlTextTags} from './types'
import isPlainObject from 'lodash.isplainobject'
import {replaceHtmlEntities } from './utils'
import {replaceHtmlEntities, forbiddenAttrChars } from './utils'

const ELEMENT_TYPES: IJsonToHtmlElementTags = {
'blockquote': (attrs: string, child: string) => {
Expand Down Expand Up @@ -507,6 +507,9 @@ export const toRedactor = (jsonValue: any,options?:IJsonToHtmlOptions) : string
}
delete attrsJson['redactor-attributes']
Object.entries(attrsJson).forEach((key) => {
if (forbiddenAttrChars.some(char => key[0].includes(char))) {
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we check if we need to return a string value here ?
Since in the next conditions the string value is being returned in case of confition failure.

}
return key[1] ? (key[1] !== '' ? (attrs += `${key[0]}="${replaceHtmlEntities(key[1])}" `) : '') : ''
})
attrs = (attrs.trim() ? ' ' : '') + attrs.trim()
Expand Down
2 changes: 2 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export function replaceHtmlEntities(str: string): string {
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}

export const forbiddenAttrChars = ['"', "'", '>','<', '/', '='];
22 changes: 21 additions & 1 deletion test/expectedJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2006,7 +2006,8 @@ export default {
`<iframe width="560" height="320" data-type="social-embeds" ></iframe><iframe allowfullscreen=\"true\"></iframe>`,
'<iframe src=\"www.youtube.com/watch?v=Gw7EqoOYC9A\" width=\"560\" height=\"320\" data-type=\"social-embeds\" ></iframe><iframe allowfullscreen=\"true\" src=\"www.youtube.com/embed/VD6xJq8NguY\"></iframe>',
`<iframe src=\"https://www.youtube.com/embed/Gw7EqoOYC9A?si=bWdnezma6qFAePQU\" width=\"560\" height=\"320\" data-type=\"social-embeds\" ></iframe><iframe allowfullscreen=\"true\" src=\"https://www.youtube.com/embed/Gw7EqoOYC9A?si=bWdnezma6qFAePQU\"></iframe>`,
`<iframe src="null" width="560" height="320" title=" This is for &lt;/p&gt;testing &lt;/p&gt; purpose 'only' " data-type="social-embeds" ></iframe>`
`<iframe src="null" width="560" height="320" title=" This is for &lt;/p&gt;testing &lt;/p&gt; purpose 'only' " data-type="social-embeds" ></iframe>`,
`<iframe 123="456" src="https://www.youtube.com/embed/Gw7EqoOYC9A?si=bWdnezma6qFAePQU" width="560" height="320" status="Active" data-type="social-embeds" ></iframe>`
],
"json":
[
Expand Down Expand Up @@ -2181,6 +2182,25 @@ export default {
},
children: [{ text: "" }],
},
{
"uid": "45a850acbeb949db86afe415625ad1ce",
"type": "social-embeds",
"attrs": {
"123": "456",
"src": "https://www.youtube.com/embed/Gw7EqoOYC9A?si=bWdnezma6qFAePQU",
"width": 560,
"height": 320,
"<p>ding": 234,
"status": "Active",
"emptyKey<": "12",
"country/": "USA"
},
"children": [
{
"text": ""
}
]
},

]

Expand Down
6 changes: 6 additions & 0 deletions test/toRedactor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,12 @@ describe("Testing json to html conversion", () => {
const html = toRedactor(json);
expect(html).toBe(expectedValue["RT-360"].html[4]);
})

it("should drop invalid attribute names",()=>{
const json = expectedValue["RT-360"].json[5]
const html = toRedactor(json);
expect(html).toBe(expectedValue["RT-360"].html[5]);
})
})

test('should convert numeric width to string', () => {
Expand Down
Loading