Skip to content

Commit

Permalink
[Fix] escape closing </script tags
Browse files Browse the repository at this point in the history
Fixes airbnb#165.
  • Loading branch information
Johannes Burghardt authored and ljharb committed Oct 11, 2019
1 parent 4bcd4e0 commit 05b2179
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 36 deletions.
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const RIGHT = '-->';
const ENCODE = [
['&', '&amp;'],
['>', '&gt;'],
['</', '&lt;/'],
];

const DATA_KEY = 'hypernova-key';
Expand Down
74 changes: 38 additions & 36 deletions test/escape-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,59 +5,61 @@ import { serialize, toScript, fromScript } from '..';

describe('escaping', () => {
it('escapes', () => {
const html = serialize('foo', '', { foo: '</script>', bar: '&gt;' });
const html = serialize('foo', '', { foo: '</script>', bar: '&gt;', baz: '</script ' });

assert.include(html, '</script&gt;');
assert.include(html, '&lt;/script&gt;');
assert.include(html, '&amp;gt;');
assert.include(html, '&lt;/script ');
});

wrap()
.withGlobal('document', () => ({}))
.describe('with fromScript', () => {
it('loads the escaped content correctly', () => {
const html = toScript({ a: 'b' }, { foo: '</script>', bar: '&gt;', baz: '&amp;' });
const $ = cheerio.load(html);
.withGlobal('document', () => ({}))
.describe('with fromScript', () => {
it('loads the escaped content correctly', () => {
const html = toScript({ a: 'b' }, { foo: '</script>', bar: '&gt;', baz: '&amp;', foobar: '</script x' });
const $ = cheerio.load(html);

global.document.querySelector = () => ({ innerHTML: $($('script')[0]).html() });
global.document.querySelector = () => ({ innerHTML: $($('script')[0]).html() });

const res = fromScript({
a: 'b',
});

assert.isObject(res);
const res = fromScript({
a: 'b',
});

assert.equal(res.foo, '</script>');
assert.equal(res.bar, '&gt;');
assert.equal(res.baz, '&amp;');
});
assert.isObject(res);

it('escapes multiple times the same, with interleaved decoding', () => {
const makeHTML = () => toScript({ attr: 'key' }, {
props: 'yay',
needsEncoding: '" &gt; </script>', // "needsEncoding" is necessary
assert.equal(res.foo, '</script>');
assert.equal(res.bar, '&gt;');
assert.equal(res.baz, '&amp;');
assert.equal(res.foobar, '</script x');
});
const script1 = makeHTML();
const script2 = makeHTML();
assert.equal(script1, script2, 'two successive toScripts result in identical HTML');

const $ = cheerio.load(script1);
it('escapes multiple times the same, with interleaved decoding', () => {
const makeHTML = () => toScript({ attr: 'key' }, {
props: 'yay',
needsEncoding: '" &gt; </script>', // "needsEncoding" is necessary
});
const script1 = makeHTML();
const script2 = makeHTML();
assert.equal(script1, script2, 'two successive toScripts result in identical HTML');

global.document.querySelector = () => ({ innerHTML: $($('script')[0]).html() });
const $ = cheerio.load(script1);

const res = fromScript({ attr: 'key' });
global.document.querySelector = () => ({ innerHTML: $($('script')[0]).html() });

const script3 = makeHTML();
assert.equal(
script1,
script3,
'third toScript after a fromScript call results in the same HTML',
);
const res = fromScript({ attr: 'key' });

assert.isObject(res);
const script3 = makeHTML();
assert.equal(
script1,
script3,
'third toScript after a fromScript call results in the same HTML',
);

assert.equal(res.props, 'yay');
assert.isObject(res);

assert.equal(res.props, 'yay');
});
});
});

it('escapes quotes and fixes data attributes', () => {
const markup = toScript({
Expand Down

0 comments on commit 05b2179

Please sign in to comment.