mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
Fixes #322 - Autoescaping doesen't work in <script> tag context
This commit is contained in:
parent
a0af1495e3
commit
4f79a8042e
@ -185,7 +185,7 @@ class Generator {
|
||||
|
||||
var beforeAfterEvent;
|
||||
|
||||
if (node.listenerCount('beforeGenerateCode') || node.listenerCount('beforeGenerateCode')) {
|
||||
if (node.listenerCount('beforeGenerateCode') || node.listenerCount('afterGenerateCode')) {
|
||||
beforeAfterEvent = new GeneratorEvent(node, this);
|
||||
}
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@ class CompileContext {
|
||||
}
|
||||
|
||||
setFlag(name) {
|
||||
this._flags[name] = true;
|
||||
this.pushFlag(name);
|
||||
}
|
||||
|
||||
clearFlag(name) {
|
||||
@ -91,6 +91,24 @@ class CompileContext {
|
||||
return this._flags.hasOwnProperty(name);
|
||||
}
|
||||
|
||||
pushFlag(name) {
|
||||
if (this._flags.hasOwnProperty(name)) {
|
||||
this._flags[name]++;
|
||||
} else {
|
||||
this._flags[name] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
popFlag(name) {
|
||||
if (!this._flags.hasOwnProperty(name)) {
|
||||
throw new Error('popFlag() called for "' + name + '" when flag was not set');
|
||||
}
|
||||
|
||||
if (--this._flags[name] === 0) {
|
||||
delete this._flags[name];
|
||||
}
|
||||
}
|
||||
|
||||
addError(errorInfo) {
|
||||
if (errorInfo instanceof Node) {
|
||||
let node = arguments[0];
|
||||
|
||||
@ -66,6 +66,18 @@ class EndTag extends Node {
|
||||
}
|
||||
}
|
||||
|
||||
function beforeGenerateCode(event) {
|
||||
if (event.node.tagName === 'script') {
|
||||
event.context.pushFlag('SCRIPT_BODY');
|
||||
}
|
||||
}
|
||||
|
||||
function afterGenerateCode(event) {
|
||||
if (event.node.tagName === 'script') {
|
||||
event.context.popFlag('SCRIPT_BODY');
|
||||
}
|
||||
}
|
||||
|
||||
class HtmlElement extends Node {
|
||||
constructor(def) {
|
||||
super('HtmlElement');
|
||||
@ -84,6 +96,9 @@ class HtmlElement extends Node {
|
||||
this.selfClosed = def.selfClosed;
|
||||
this.dynamicAttributes = undefined;
|
||||
this.bodyOnlyIf = undefined;
|
||||
|
||||
this.on('beforeGenerateCode', beforeGenerateCode);
|
||||
this.on('afterGenerateCode', afterGenerateCode);
|
||||
}
|
||||
|
||||
generateHtmlCode(codegen) {
|
||||
|
||||
@ -43,10 +43,16 @@ class Text extends Node {
|
||||
let builder = codegen.builder;
|
||||
|
||||
if (escape) {
|
||||
let escapeFuncVar = 'escapeXml';
|
||||
|
||||
if (codegen.context.isFlagSet('SCRIPT_BODY')) {
|
||||
escapeFuncVar = codegen.addStaticVar('escapeScript', '__helpers.xs');
|
||||
}
|
||||
|
||||
// TODO Only escape the parts that need to be escaped if it is a compound expression with static
|
||||
// text parts
|
||||
argument = builder.functionCall(
|
||||
'escapeXml',
|
||||
escapeFuncVar,
|
||||
[argument]);
|
||||
} else {
|
||||
argument = builder.functionCall(builder.identifier('str'), [ argument ]);
|
||||
|
||||
@ -22,6 +22,7 @@ var attr = require('raptor-util/attr');
|
||||
var isArray = Array.isArray;
|
||||
var STYLE_ATTR = 'style';
|
||||
var CLASS_ATTR = 'class';
|
||||
var escapeEndingScriptTagRegExp = /<\//g;
|
||||
|
||||
function notEmpty(o) {
|
||||
if (o == null) {
|
||||
@ -197,6 +198,26 @@ module.exports = {
|
||||
* @private
|
||||
*/
|
||||
xa: escapeXmlAttr,
|
||||
|
||||
/**
|
||||
* Escapes the '</' sequence in the body of a <script> body to avoid the `<script>` being
|
||||
* ended prematurely.
|
||||
*
|
||||
* For example:
|
||||
* var evil = {
|
||||
* name: '</script><script>alert(1)</script>'
|
||||
* };
|
||||
*
|
||||
* <script>var foo = ${JSON.stringify(evil)}</script>
|
||||
*
|
||||
* Without escaping the ending '</script>' sequence the opening <script> tag would be
|
||||
* prematurely ended and a new script tag could then be started that could then execute
|
||||
* arbitrary code.
|
||||
*/
|
||||
xs: function(val) {
|
||||
return (typeof val === 'string') ? val.replace(escapeEndingScriptTagRegExp, '\\u003C/') : val;
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal method to render a single HTML attribute
|
||||
* @private
|
||||
|
||||
3
test/autotests/render/escape-script/expected.html
Normal file
3
test/autotests/render/escape-script/expected.html
Normal file
@ -0,0 +1,3 @@
|
||||
<script>
|
||||
var foo = {"name":"Evil \u003C/script>"};
|
||||
</script><pre>{"name":"Evil </script>"}</pre>
|
||||
4
test/autotests/render/escape-script/template.marko
Normal file
4
test/autotests/render/escape-script/template.marko
Normal file
@ -0,0 +1,4 @@
|
||||
<script>
|
||||
var foo = ${JSON.stringify(data.foo)};
|
||||
</script>
|
||||
<pre>${JSON.stringify(data.foo)}</pre>
|
||||
5
test/autotests/render/escape-script/test.js
Normal file
5
test/autotests/render/escape-script/test.js
Normal file
@ -0,0 +1,5 @@
|
||||
exports.templateData = {
|
||||
foo: {
|
||||
name: 'Evil </script>'
|
||||
}
|
||||
};
|
||||
@ -1 +1 @@
|
||||
<script>document.write('<div>Hello <script>evil<script></div>');</script>
|
||||
<script>document.write('<div>Hello <script>evil\u003C/script></div>');</script>
|
||||
@ -1,3 +1,3 @@
|
||||
exports.templateData = {
|
||||
"name": "<script>evil<script>"
|
||||
"name": "<script>evil</script>"
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user