config that disallows eval in htmx implementation

addressed https://github.com/bigskysoftware/htmx/issues/305
This commit is contained in:
carson 2021-01-04 10:36:56 -07:00
parent 3c7dde7e1f
commit 58f373d1e5
5 changed files with 42 additions and 8 deletions

View File

@ -42,6 +42,7 @@ return (function () {
requestClass:'htmx-request',
settlingClass:'htmx-settling',
swappingClass:'htmx-swapping',
allowEval:true,
attributesToSettle:["class", "style", "width", "height"]
},
parseInterval:parseInterval,
@ -248,7 +249,9 @@ return (function () {
//==========================================================================================
function internalEval(str){
return eval(str);
return maybeEval(getDocument().body, function () {
return eval(str);
});
}
function onLoadHelper(callback) {
@ -735,7 +738,7 @@ return (function () {
last !== ".";
}
function maybeGenerateConditional(tokens, paramName) {
function maybeGenerateConditional(elt, tokens, paramName) {
if (tokens[0] === '[') {
tokens.shift();
var bracketCount = 1;
@ -752,7 +755,10 @@ return (function () {
tokens.shift();
conditionalSource += ")})";
try {
var conditionFunction = Function(conditionalSource)();
var conditionFunction = maybeEval(elt,function () {
return Function(conditionalSource)();
},
function(){return true})
conditionFunction.source = conditionalSource;
return conditionFunction;
} catch (e) {
@ -800,7 +806,7 @@ return (function () {
triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)});
} else {
var triggerSpec = {trigger: trigger};
var eventFilter = maybeGenerateConditional(tokens, "event");
var eventFilter = maybeGenerateConditional(elt, tokens, "event");
if (eventFilter) {
triggerSpec.eventFilter = eventFilter;
}
@ -1215,7 +1221,9 @@ return (function () {
function evalScript(script) {
if (script.type === "text/javascript" || script.type === "") {
try {
Function(script.innerText)();
maybeEval(script, function () {
Function(script.innerText)()
});
} catch (e) {
logError(e);
}
@ -1803,9 +1811,18 @@ return (function () {
return getValuesForElement(parentElt(elt), attr, strToValues, expressionVars);
}
function maybeEval(elt, toEval, defaultVal) {
if (htmx.config.allowEval) {
return toEval();
} else {
triggerErrorEvent(elt, 'htmx:evalDisallowedError');
return defaultVal;
}
}
function getHXVarsForElement(elt, expressionVars) {
return getValuesForElement(elt, "hx-vars", function(valueStr){
return Function("return (" + valueStr + ")")()
return maybeEval(elt,function () {return Function("return (" + valueStr + ")")();}, {});
}, expressionVars);
}

View File

@ -246,5 +246,20 @@ describe("Core htmx API test", function(){
}
});
it('eval can be suppressed', function () {
var calledEvent = false;
var handler = htmx.on("htmx:evalDisallowedError", function(){
calledEvent = true;
});
try {
htmx.config.allowEval = false;
should.equal(htmx._("tokenizeString"), undefined);
} finally {
htmx.config.allowEval = true;
htmx.off("htmx:evalDisallowedError", handler);
}
calledEvent.should.equal(true);
});
})
})

View File

@ -34,7 +34,7 @@ describe("Core htmx tokenizer tests", function(){
it('generates conditionals property', function()
{
var tokens = tokenize("[code==4||(code==5&&foo==true)]");
var conditional = htmx._("maybeGenerateConditional")(tokens);
var conditional = htmx._("maybeGenerateConditional")(null, tokens);
var func = eval(conditional);
func({code: 5, foo: true}).should.equal(true);
func({code: 5, foo: false}).should.equal(false);

View File

@ -95,6 +95,7 @@ Note that using a [meta tag](/docs/#config) is the preferred mechanism for setti
* `requestClass:'htmx-request'` - string: the class to place on triggering elements when a request is in flight
* `settlingClass:'htmx-settling'` - string: the class to place on target elements when htmx is in the settling phase
* `swappingClass:'htmx-swapping'` - string: the class to place on target elements when htmx is in the swapping phase
* `allowEval:true` - boolean: allows the use of eval-like functionality in htmx, to enable `hx-vars`, trigger conditions & script tag evaluation. Can be set to `false` for CSP compatibility
##### Example

View File

@ -817,6 +817,7 @@ Htmx allows you to configure a few defaults:
| `htmx.config.requestClass` | defaults to `htmx-request`
| `htmx.config.settlingClass` | defaults to `htmx-settling`
| `htmx.config.swappingClass` | defaults to `htmx-swapping`
| `htmx.config.allowEval` | defaults to `true`
</div>