Skip to content

Commit 904f30d

Browse files
authored
Merge pull request #85 from ember-fastboot/shoebox-encoding
JSON escape rendered shoebox content
2 parents 9899016 + 08d6e0a commit 904f30d

3 files changed

Lines changed: 42 additions & 15 deletions

File tree

src/ember-app.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,10 @@ function createShoebox(doc, fastbootInfo) {
310310
if (!shoebox.hasOwnProperty(key)) { continue; }
311311

312312
let value = shoebox[key];
313-
let scriptText = doc.createTextNode(JSON.stringify(value));
313+
let textValue = JSON.stringify(value);
314+
textValue = escapeJSONString(textValue);
315+
316+
let scriptText = doc.createRawHTMLSection(textValue);
314317
let scriptEl = doc.createElement('script');
315318

316319
scriptEl.setAttribute('type', 'fastboot/shoebox');
@@ -322,6 +325,22 @@ function createShoebox(doc, fastbootInfo) {
322325
return RSVP.resolve();
323326
}
324327

328+
const JSON_ESCAPE = {
329+
'&': '\\u0026',
330+
'>': '\\u003e',
331+
'<': '\\u003c',
332+
'\u2028': '\\u2028',
333+
'\u2029': '\\u2029'
334+
};
335+
336+
const JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/g;
337+
338+
function escapeJSONString(string) {
339+
return string.replace(JSON_ESCAPE_REGEXP, function(match) {
340+
return JSON_ESCAPE[match];
341+
});
342+
}
343+
325344
/*
326345
* Builds a new FastBootInfo instance with the request and response and injects
327346
* it into the application instance.

test/fastboot-shoebox-test.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const FastBoot = alchemistRequire('index');
1010

1111
describe("FastBootShoebox", function() {
1212

13-
it("can render the shoebox HTML", function() {
13+
it("can render the escaped shoebox HTML", function() {
1414
var fastboot = new FastBoot({
1515
distPath: fixture('shoebox')
1616
});
@@ -20,6 +20,11 @@ describe("FastBootShoebox", function() {
2020
.then(html => {
2121
expect(html).to.match(/<script type="fastboot\/shoebox" id="shoebox-key1">{"foo":"bar"}<\/script>/);
2222
expect(html).to.match(/<script type="fastboot\/shoebox" id="shoebox-key2">{"zip":"zap"}<\/script>/);
23+
24+
// Special characters are JSON encoded, most notably the </script sequence.
25+
expect(html).to.include('<script type="fastboot/shoebox" id="shoebox-key4">{"nastyScriptCase":"\\u003cscript\\u003ealert(\'owned\');\\u003c/script\\u003e\\u003c/script\\u003e\\u003c/script\\u003e"}</script>');
26+
27+
expect(html).to.include('<script type="fastboot/shoebox" id="shoebox-key5">{"otherUnicodeChars":"\\u0026\\u0026\\u003e\\u003e\\u003c\\u003c\\u2028\\u2028\\u2029\\u2029"}</script>');
2328
});
2429
});
2530

test/fixtures/shoebox/fastboot/fastboot-test.js

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

0 commit comments

Comments
 (0)