Skip to content

Instantly share code, notes, and snippets.

@voxpelli
Last active August 25, 2021 14:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save voxpelli/ff7a83406078ba2d68b738e63cad6498 to your computer and use it in GitHub Desktop.
Save voxpelli/ff7a83406078ba2d68b738e63cad6498 to your computer and use it in GitHub Desktop.
HTML safe JSON escaping, see eg: https://github.com/ember-fastboot/fastboot/pull/85
// My own take
const JSON_ESCAPE = {
'&': '\\u0026',
'>': '\\u003e',
'<': '\\u003c',
'\u2028': '\\u2028',
'\u2029': '\\u2029'
};
const JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/g;
const jsonStringifyForScriptTag = (obj) =>
JSON.stringify(obj)
.replace(JSON_ESCAPE_REGEXP, match => JSON_ESCAPE[match]);
// Extracted from https://github.com/ember-fastboot/ember-cli-fastboot/blob/909c1417ceeb8a5c92bb952b0d59be02bfdca546/packages/fastboot/src/ember-app.js#L406-L420
// Discussion in https://github.com/ember-fastboot/fastboot/pull/85
const JSON_ESCAPE = {
'&': '\\u0026',
'>': '\\u003e',
'<': '\\u003c',
'\u2028': '\\u2028',
'\u2029': '\\u2029'
};
const JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/g;
function escapeJSONString(string) {
return string.replace(JSON_ESCAPE_REGEXP, function(match) {
return JSON_ESCAPE[match];
});
}
const React = require('react');
const { renderToStaticMarkup } = require('react-dom/server');
const JSON_ESCAPE = {
'&': '\\u0026',
'>': '\\u003e',
'<': '\\u003c',
'\u2028': '\\u2028',
'\u2029': '\\u2029'
};
const JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/g;
function escapeJSONString(value) {
return value.replace(JSON_ESCAPE_REGEXP, match => JSON_ESCAPE[match]);
}
function escapedJSONStringify(obj) {
return escapeJSONString(JSON.stringify(obj));
}
const data = "</script><script>console.log('hejsan2')</script><script>";
// outputs: <script type="application/ld+json">"</script><script>console.log('hejsan2')</script><script>"</script>
// which won't parse as expected + will log 'hejsan2' to the console
console.log(renderToStaticMarkup(React.createElement('script', {
type: 'application/ld+json',
dangerouslySetInnerHTML: { __html: `${JSON.stringify(data)}` }
})));
// outputs: <script type="application/ld+json">"\u003c/script\u003e\u003cscript\u003econsole.log('hejsan2')\u003c/script\u003e\u003cscript\u003e"</script>
// which can be parsed as expected + won't log anything
// parsing it: JSON.parse(`"\u003c/script\u003e\u003cscript\u003econsole.log('hejsan2')\u003c/script\u003e\u003cscript\u003e"`)
// results in: "</script><script>console.log('hejsan2')</script><script>"
console.log(renderToStaticMarkup(React.createElement('script', {
type: 'application/ld+json',
dangerouslySetInnerHTML: { __html: `${escapedJSONStringify(data)}` }
})));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment