add safe eval for browser and eval option#185
Conversation
|
@brettz9 Could you please check and see if the approach is right ? I particularly need advice on the rollup/babel/eslint configuration changes as I'm totally new to them. Also, if possible, how should we go with the support of If I get a green flag in these, I'll work on documentation. |
update test html file to use compiled module update demo html file to include sample & prevent submit
|
I don't have time to look at this now, and no guarantees about getting to it, but I think an optimal solution, if you can't get the multi-line evaluation supported, would be to allow the user to supply their own evaluator, e.g., optionally passing in |
|
user still has the choice to go with unsafe way using a new options |
|
@brettz9 Looks like the PR is complete. I'm in no rush, so whenever you (or some other contributor) find time, please look into it and suggest changes. |
brettz9
left a comment
There was a problem hiding this comment.
I plan to give a deeper review later, but wanted to first address these smaller questions, and also ask that we maintain 100% testing coverage. (I see that the coverage badge is no longer reporting 100%, so some of the new lines of code apparently aren't covered in tests.)
I'd prefer we avoid the Babel ESLint parser unless there is really a compelling reason, though it'd be fine to increase the parserOptions.ecmaVersion to use the latest standard features in source.
From what I can see, the rest all looks very good.
@brettz9, my two unsolicited cents are in agreement with your thoughts about this PR for a few couple reasons.
const customEval = (code: string, context: any): any => {
// evaluate code against context, return any matching result(s)
};
const jsonPath = new JSONPath({ eval: customEval });
jsonPath.evaulate('$.test');An alternative API that fits into the current architecture a bit better, which would require the consumer to pass in a class to the config. class CustomEval {
constructor(code: string) {
// any compiling you need to do.
this.code = code;
}
eval(context: any) {
// however you'd like to evaluate the code (`this.code`) against `context`
// return undefined, or match(es)
return undefined;
}
}
const jsonPath = new JSONPath({ eval: CustomEval });
jsonPath.evaluate('$.test');In both scenarios, this library would still replace the shorthand properties(ex While option 2 has a bit more boilerplate, I think it provides more flexibility for consumers of this library and it enables automatic caching of the compiled script. |
|
@jacobroschen : Thank you for your thoughts. They are most welcome. However, I have a few thoughts in response: As far as adding dependencies, the bundle size is rather good, no less considering what it is doing:
And although it does not support everything eval-wise, for the much more common use case of just accessing properties, it really does deliver something important. I agree we can drop It has been a long-time goal for us to have a safe default, and recently we had still another request for a safe default: #182 . I rejected that because I didn't want to gut the core functionality our users have become accustomed to, but only because we didn't have an alternative. I remain open to further thoughts, as well as to input of others, but unless there are concerns with jsep specifically, it seems like a hearty compromise without coming at much cost. |
|
Your API proposal looks sound (I agree with the second one too) and perhaps this PR can be adjusted to implement. |
|
I agree with @brettz9 . The primary reason why I decided to use jsep in this library was to provide a safe & lightweight evaluation out of the box. Another similar library jsonpath achieves this by using static-eval and esprima which have minified + gzip sizes as
However, the idea of allowing the library user to provide his own |
|
I have implemented the new API eliminating |
evalType optioneval option
|
will this PR ever be merged? |
`ignoreEvalErrors` can be used to supress errors in eval expressions. These errors are common because the expression might be suitable for a particular value but may give error on other values. For such scenarios, we expect it to match the passing values instead of crash entirely
|
@guoliang Thanks for reminding @brettz9 I have removed the conflicts which had appeared during the time. Also, since your last review, I added a new option |
brettz9
left a comment
There was a problem hiding this comment.
If you can make the mentioned changes, I think I'll be ready for a final review. Looks good so far...
…Error=false to avoid test breaks
|
@brettz9 All resolved. |
|
I added one commit to fully pass linting and the testing scripts. Did you mean for the Also, please prepare a message for those upgrading to this breaking change version (e.g., what users of |
|
I hope this message suffices. |
|
If you want to take one last look, I think it should be ready for a release now. |
|
Tried few expressions in browser demo only, and it looks good to me. |
|
Released as v9.0.0. Thanks for your contributions! |
Adding a safe alternative to Function/eval in browser.
This is also required since the chrome extensions & chrome apps have already become strict about safety.
I was trying to use it in a chrome extension but couldn't because of unsafe-eval. Hence this fix tries to introduce a safe evaluation method which satisfies Content Security Policy.
eval: "safe"is effective only in browser and doesn't uses a scripting engine which supports a minimal form of javascript (no functions or complex expressions).PR description
eval: "safe" | "native" | boolean | (code, context) => value | Script)ignoreEvalError: booleanwhich can be used to consider the errors in eval expressions as match.Checklist
npm test, ensuring linting passesFixes #60 , #182 , #169