I have a URL, that I am parsing after the hash. The content after the hash is a math equation (eg. http://example.com/something#5+1) which I would like to find the sum of (or the result of any other equation like a product, division, etc)
I can retrieve the numbers using:
var url = (window.location.hash).substr(1) // returns "5+1" as a string
Although I find if I try to convert this to a number it doesn't actually do the math. It cuts it down to 5, instead of showing the sum of 8.
Is this kind of conversion possible?
thanks!
Do not eval() arbitrary code from the URL as it can easily be exploited for XSS. I have created a library called JSandbox that can sandbox JavaScript code execution, but it requires support for web workers. It would not be a good idea to use fake worker support for IE as then the safety of the sandbox is gone.
Your code would go as follows:
JSandbox.eval("with(Math){" + location.hash.substr(1) + "}", function (res) {
// handle the results here
});
Use this to also handle errors:
JSandbox.eval("with(Math){" + location.hash.substr(1) + "}", function (res) {
// handle the results here
}, null, function (err) {
// handle errors here
});
I included a with (Math) { ... } wrapper so the hash code has short access to Math functions. (eg. abs(..) instead of Math.abs(..))
To really do this correctly, you need to write a simple parser for your mathematical expression language. This is allegedly not very hard, but I myself have never been able to do it. This is the only way to get the javascript to evaluate and interpret the math expression correctly, without also opening pandoras box, and letting all kinds of nasty stuff through like a simple (and stupid) call to eval() will.
Or you can just have a bit of a look around and find someone who has already done this such as here:
http://silentmatt.com/math/evaluator.php
eval() is the easiest way to perform the calculation, but you'll definitely want to verify that your input is sane:
var input = window.location.hash.substr(1);
var result = null;
try {
// Make sure the input is only numbers and supported operators.
if (/^[-+*/.()0-9]+$/.test(input))
result = eval(input);
} catch (ex) {
// Insert error handling here...
}
This regex should filter out any dangerous input.
var code = "5+1";
var result = window.eval(code);
But as in all languages that has eval, be careful with what you eval.
To execute a string see eval and some reasons not to do this are at why-is-using-javascript-eval-function-a-bad-idea.
This means in code of any importance—with data that is coming from an untrusted source (e.g. the internet)—you should parse out the numbers and the mathematical operation...and not accept any other types of input.
function CalculateString(hash) {
var ReturnValue;
var patt = '([\d*+-/.%])';
ReturnValue = hash.match(patt)[1];
ReturnValue = eval(ReturnValue);
if (ReturnValue > 0) {
return parseInt(ReturnValue,10);
} else {
return 0;
}
}
So you can do like this:
var Hash = (window.location.hash).substr(1);
var Calculation = CalculateString(Hash); // Retinerer result of the calculation if it is valid, otherwise it will give you 0.
Related
Currently I am using the following to evaluate variables that are placed in strings at runtime:
newVal = eval("`" + newVal + "`");
So if I have the string:
"Hello from channel: ${erpVars["CommandChannel"]["name"]}"
And erpVars["CommandChannel"]["name"] has value home, then the resulting string is:
Hello from channel: home
There are other objects than just erpVars that could be holding matching values for the string, but this is just one example. It's also important to note that each string could have more than one variable that needs replacing.
I am trying to achieve the same thing without using eval(), as some of the variable values come from user input.
Your case sounds super nasty (you should never ever use eval in JS! It poses a major security threat! also it looks weird that you want to replace this sort of a string) and perhaps if you told me more about where you get your inputs from and in what form, then maybe we could find together a much better solution for this. On that note, this is how I would solve your issue in its current form.
const newVal = 'Hello from channel: ${erpVars["CommandChannel"]["name"]}';
const strings = {
erpVars: {
CommandChannel: {
name: "home"
}
}
};
const vars = newVal.match(/\$\{.+?\}/g);
let result = newVal;
vars.forEach(v => {
let valuePath = '${erpVars["CommandChannel"]["name"]}'.match(/[\w\d]+/g).join('.');
result = result.replace(v, _.get(strings, valuePath));
});
console.log(result);
Note that I'm skipping here the edge scenarios, like getting a null result from the newVal.match when there are no variables in the newVal, but that's easy to handle.
Also note that over here i'm using the lodash library in _.get() (https://lodash.com/docs/4.17.15#get). It's super popular for this kind of small tasks. Of course there are really a lot of other tools that allow you to extract a value based on a property path like erpVars.CommandChannel.name that is stored in the valuePath variable, including a crazy amount of instructions that tell you how to do it yourself.
I'm working on a command for a discord bot:
Someone types /calc (some-math-expression), eg. /calc 4+5.
I'd like to evaluate 4+5 and display the answer.
For this, I believe I have to take the '4+5' out of the string, calculate it, and return the answer.
How do I do it?
I tried doing this, it may be stupid, I'm new to this. (I'm using else if because I have other inputs for the bot)
else if (message.content === '/calc' + exp) {
return Number(exp);
}
Apparently, this doesn't assign the '(some-math-expression)' to the exp var which I've defined before.
The bot shows no output.
Is there a method that splits the string into /calc and something else I could assign to a variable automatically?
Thanks!
While this answer would work, this could be used in a malicious way: the code will run everything in the string, so if somebody writes the right thing they could insert code into the bot, making it vulnerable to attacks. They could, for example, turn it off with /calc client.destroy() or read its token with /calc client.token: it's good practice not to make the eval command publicly accessible.
Instead of that, I would use a more secure method, with the mathjs package.
You can parse the expression as said in other answers, then use math.eval() to make it resolve the expression. You can find the docs here.
Here's a quick example:
var mathjs = require("mathjs");
let cmdString, mathExpression;
// This will just return the expression
function getExp(command = '') {
return command.split('/calc')[1].trim();
}
cmdString = "/calc4+5"; // If this is the command...
mathExpression = getExp(cmdString); // ...this will be '4+5'
// Make the result with mathjs.eval()
let result = mathjs.eval(mathExpression); // 9
This is an easy way that works even with more complex operations, like sqrt() and cos(). It will also work with imaginary numbers and all sorts of stuff that no one would ever ask to a Discord bot.
You can try the package with RunKit: link.
The easiest way for you to parse your input would be to use String.split. That is...
const words = message.content.split(' ');
const command = words[0];
const variables = words.splice(1).join(' ');
here command will become '/calc' and variables will become '4+5'
This works because in any input that you need your discord bot to handle, the first word will always be the command.
let message = '/calc 4+5'
let equation = message.replace(/\/calc/, '').trim();
let answer = eval(equation)
console.log(equation+' =', answer )
You can achieve your function using the following Regular expression.
let message = '/calc 4+5'
if (equation = message.match(/^\/calc(.+)/)) {
let answer = eval(equation[1].trim());
console.log(equation[1]+' =',answer)
}
I an not sure how you are getting the message.content and exp. But, as per my understanding you can do something as follows:
let cmdString = "/calc4+5";
let mathExpression = cmdString.split("/calc")[1];
let result = eval(mathExpression);
result is what your resultant values of the expression.
Thanks...
My code need to execute a forumla (like Math.pow(1.05, mainObj.smallObj.count)).
My path is :
var path = mainObj.smallObj.count;
as you can see.
If needed, my code can split all variable names from this path and put it in an array to have something like :
var path = ["mainObj", "smallObj", "count"];
Since I don't want to use eval (this will cause memory leaks as it will be called many times every seconds), how can I access it from window?
Tried things like window["path"] or window.path.
If it is always unclear, let me know.
Thanks in advance for any help.
EDIT: forget to tell that some config are written in JSON, so when we take the formula, it's interpreted as "Math.pow(1.05, mainObj.smallObj.count)" so as a string.
I would say there are better solutions then eval, but it depends how the forumla can be structured. It could be precompiled using new Function (this is also some kind of eval) but allowing it to be called multiple times without the need to recompile for each invocation. If it is done right it should perform better then an eval.
You could do something like that:
var formula = {
code : 'Math.pow(1.05, mainObj.smallObj.count)',
params : ['mainObj']
}
var params = formula.params.slice(0);
params.push('return '+formula.code);
var compiledFormula = Function.apply(window, params);
//now the formula can be called multiple times
var result = compiledFormula({
smallObj: {
count: 2
}
});
You can get the path part reconciled by recursively using the bracket notation:
window.mainObj = { smallObj: { count: 2 } };
var path = ["mainObj", "smallObj", "count"];
var parse = function (obj, parts) {
var part = parts.splice(0, 1);
if (part.length === 0) return obj;
obj = obj[part[0]];
return parse(obj, parts);
};
var value = parse(window, path);
alert(value);
Basically, parse just pulls the first element off the array, uses the bracket notation to get that object, then runs it again with the newly shortened array. Once it's done, it just returns whatever the result of the last run is.
That answers the bulk of your question regarding paths. If you're trying to interpret the rest of the string, #t.niese's answer is as good as any other. The real problem is that you're trusting code from an external source to run in the context of your app, which can be a security risk.
I have a requirement that the user can provide arbitrary statements which can be stored in a function and called later to get a return value. A simple example of this is that userInput might be
var x = 10;
x;
I would store this via
var callback = function() {
return eval(userInput);
}
and then running callback() returns 10 as expected.
However, I also need to support the case with an explicit return statement, ie userInput might be
var x = 10;
return x;
In this case the eval method above will fail with SyntaxError: return not in function. Instead I could store callback as
var callback = new Function(userInput);
My issue is that I would like to combine these two approaches according the rule 'get explicit return value otherwise get the result of the last executed statement'. In particular this can't be done with analysis of the code at callback creation time as the user could potentially do something odd like
if(envVar < 10)
return a;
b * 0.5;
which combines both.
Any thoughts on how to structure the creation of the callback function to accommodate these possible inputs? Unfortunately it is not possible to enforce one style or the other on the user.
UPDATE to answer some of the comments below.
One solution suggested is to search for a return token and choose between new Function and eval. This doesn't work for my last example, see http://jsfiddle.net/ZGb6z/2/ - out4 should be "no" but ends up being undefined as the last executed statement is not returned.
Another suggestion is to modify the user input to add an explicit return on the last line if one is not found. Unfortunately it's not possible to know which statement will be executed last. Consider
var x = 10;
switch(x) {
case 10:
100;
break;
default:
200;
break;
}
When called it should return 100, but it would take some serious analysis to determine where to put returns for arbitrary code.
Just use a try catch, manipulating the input will be very painful for you, and try catch can't really make your code any more obtuse at this point.
var failback = function () {
try {
return eval(userInput);
} catch (e) {
return Function(userInput);
}
};
What I would really suggest is investing in a parser, kind of like how Angular does it. That kind of thing would prevent your users from doing whatever the hell they want, introducing attack vectors, yadda, yadda, yadda.
Either manage your expectations or manage your user's expectations. eval and new Function() are not suitable for your requirements if you require mixed usage of explicit and non-explicit return statements in the same user-input. You will continue to find issues following either of these routes.
Simply searching for the word return is not sufficient either... var returning = true; or var a = 'return'; or /* return true */ true; will all throw false positives.
Managing your expectations: To do such a thing you require a form of lexer and parser, at which point you can do away with eval entirely and execute your own safe functions based on the parsed input. This is the best approach when execution of user input has to occur anyway as you can ensure that nothing gets executed you do not wish to permit. If you want to cover these sort of edge cases and permit strange user input then you must be prepared to increase the size and development time of your application. I have built a few applications executing user generated code and have always come to the conclusion this is the correct route to go down.
Managing your user's expectations: Provide a guide, tell them not to mix explicit returns with non-explicit returns, these are strange coding practices anyway. Better yet explicitly tell them to include or omit the return statement. There is no shame in asking your users to follow them, especially if it allows you to improve their experience elsewhere.
There I was thinking I'd only see problems like this at the code golf stack exchange :)
My solution is here: http://jsfiddle.net/hKq87/1
It essentially replaces the 'return' statement with an exception that has a special string prefixed to it. If we see that string, we know we are actually returning a value, and return it rather than re-raising the exception.
The reason I chose to throw an exception rather than replace the return statement with a function call was because it is hard to know where the JS code evaluated for the return really ends. It could be split across multiple lines, contain several special characters and may not even have the optional semi-colon at the end. So I concatenate a string to whatever the value being returned is and throw it, as the throw keyword doesn't require it's argument to be wrapped in parentheses.
In addition, throwing exceptions provides me a convenient way to immediately terminate execution of the code block, without halting other JS execution.
Here is the callback method:
var callback = function(userInput) {
var returned = undefined;
userInput = userInput.replace(/(^|[\(\\)[\]{};,\s])return(\s*[^\s;])?/gi, function(m, b, e){
return b + " throw '__RETURNED_VALUE'" +
(e !== undefined ? "+" + e : "");
});
try {
returned = eval(userInput);
} catch (e) {
if (e.indexOf("__RETURNED_VALUE") == 0) {
returned = e.substring("__RETURNED_VALUE".length) || undefined;
}
else {
throw e;
}
}
return returned;
}
The regex above accounts for variables that may end with the string "return", that we would not want to replace as it is not a return statement. It also allows for return statements within braces, without trailing semi-colons or at the very beginning/end.
One issue with the current method is that you can not use the (rare) comma operator in a return statement, or expect numerical values to be returned correctly. The last test case in the jsfiddle demonstrates this. An example from here:
//original
return 5 * 2 + 3, 22;
//modified
throw '__RETURNED_VALUE='+ 5 * 2 + 3, 22;
//apply * operator
throw '__RETURNED_VALUE='+ 10 + 3, 22;
//apply + operators
throw '__RETURNED_VALUE=103', 22;
//apply , operator
throw 22;
This problem can be avoided by completely eliminating the prefix '__RETURNED_VALUE=' and just replacing 'return' with 'throw'. However, this means that the code provided must run without throwing exceptions, which I thought to be a harder constraint than just crafting return statements to be simple (avoiding comma operators, non-parenthesized arithmetic, etc.). In addition, if a user ever creates a return statement that we can't handle with the current code, we conveniently throw an exception for it so it easily comes to our attention.
jsFiddle Demo
Lets assume your user can be a little smarter than the average bear. We are going to ask them to specifically provide an initial value and then a callback with an expression for that value.
The main benefit of doing this is that you avoid eval, and actually have a nice implementation that is re-usable as opposed to being subject to later refactoring.
This way also provides a separation of where the input comes from and where the examination comes from. Although the provided example only shows integer input, really it could be another call with absolutely no knowledge of the value aside that it needs to conform to the callback logic.
function expression(x,callback){
return callback(x);
}
out1.innerHTML = expression(8,function(x){
return x;
});
out2.innerHTML = expression(10,function(x){
return x;
});
out3.innerHTML = expression(10,function(x){
if(x === 10) return "yes"; "no";
});
out4.innerHTML = expression(8,function(x){
return x === 10 ? "yes" : "no";
});
I have a function e.g.
var test = function () {alert(1);}
How can I get the body of this function?
I assume that the only way is to parse the result of test.toString() method, but is there any other way? If parsing is the only way, what will be the regex to get to body? (help with the regex is extremly needed, because I am not familiar with them)
IF(!!!) you can get the toString(), then you can simply take the substring from the first indexOf("{") to the lastIndexOf("}"). So, something like this "works" (as seen on ideone.com):
var test = function () {alert(1);}
var entire = test.toString(); // this part may fail!
var body = entire.substring(entire.indexOf("{") + 1, entire.lastIndexOf("}"));
print(body); // "alert(1);"
2015 update
Upon revisiting the state of function decompilation, it can said that it's generally safe in certain well-considered use cases and enviroments (e.g: Node.js workers with user defined functions).
It should be put in the same bucket as eval, which is a powerful tool that has its place, but should only be used on rare occasions. Think twice, that's my only advice.
The conclusions from Kangax's new research:
It's still not standard
User-defined functions are generally looking sane
There are oddball engines (especially when it comes to source code
placement, whitespaces, comments, dead code)
There might be future oddball engines (particularly mobile or unusual
devices with conservative memory/power consumption)
Bound functions don't show their original source (but do preserve
identifier... sometimes)
You could run into non-standard extensions (like Mozilla's expression
closures)
ES6 is coming, and functions can now look very different than
they used to
Minifiers/preprocessors are not your friend
"function decompilation" — a process of getting
string representation of a Function object.
Function decompilation is generally
recommended against, as it is a
non-standard part of the language, and
as a result, leads to code being
non-interoperable and potentially
error-prone.
#kangax on comp.lang.javascript
Simplest Use-Case
If you just want to execute the body of the function (e.g. with eval or using the Worker API), you can simply add some code to circumvent all the pitfalls of extracting the body of the function (which, as mentioned by others, is a bad idea in general):
'(' + myFunction + ')()';
I am using this trick in this Worker-related JSFiddle.
Complete Function Serialization With Accurate Stacktrace
I also wrote a more complete library that can:
Serialize any kind of function to string
Be able to send that string representation anywhere else, execute it with any custom arguments, and be able to reproduce the original stacktrace
Check out my CodeBuilder code here.
Note that much of the code takes care of making sure that we get an accurate stacktrace, wherever we execute the serialized function at a later point in time.
This fiddle demonstrates a simplified version of that logic:
Use JSON.stringify to properly serialize the function (that comes in handy when, e.g., we want to make it part of a bigger serialization "data package").
We then wrap it in one eval to un-escape the "JSON-ish"-escaped string (JSON does not allow functions + code, so we must use eval), and then in another eval to get back the object we wanted.
We also use //# sourceMappingURL (or the old version //# sourceMappingURL) to show the right function name in the stacktrace.
You will find that the Stacktrace looks Ok, but it does not give you the correct row and column information relative to the file that we defined the serialized functions in, which is why my Codebuilder makes use of stacktracejs to fix that.
I use the CodeBuilder stuff in my (now slightly dated) RPC library where you can find some examples of how it is used:
serializeInlineFunction example
serializeFunction example
buildFunctionCall example
extending #polygenelubricants' answer:
using: .toString()
Testee:
var y = /* olo{lo} */
/* {alala} */function/* {ff} */ x/*{s}ls{
}ls*/(/*{*{*/)/* {ha-ha-ha} */
/*
it's a function
*/
{
return 'x';
// }
}
/*
*/
By indexOf and lastIndexOf:
function getFunctionBody(fn) {
function removeCommentsFromSource(str) {
return str.replace(/(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, '$1');
}
var s = removeCommentsFromSource( fn.toString() );
return s.substring(s.indexOf('{')+1, s.lastIndexOf('}'));
};
getFunctionBody(y);
/*
"
return 'x'
"
*/
used: rm comments from js source
This code provides the body when using ES6 arrow functions like var testFn=(q)=>q+1;
function getFunctionBody(test){
var entire = test.toString(); // note: not safe-guarded; this part may fail like this!
return entire.substring((entire.indexOf("{")+1)||(entire.indexOf("=>")+2), entire.lastIndexOf("}")!==-1?entire.lastIndexOf("}"):entire.length);
}
//testing/showcase code
var tests = [
function () {alert(1);},
()=>{return 1;},
q=>q+1
];
for (var i=0;i<tests.length;i++){
console.log(tests[i],getFunctionBody(tests[i]));
}
I originally submitted this code as an edit to polygenelubricants accepted answer, but it was rejected as the changes were considered to be too drastic.
var fn1 = function() {};
var fn2 = function() { alert("lol!"); };
Function.prototype.empty = function() {
var x = this.toString().match(/\s*function\s*\w*\s*\(.*?\)\s*{\s*}\s*;?\s*/);
return x != null;
};
alert(fn1.empty()); // true
alert(fn2.empty()); // false
'
Solução proposta pelo Paulo Torres no grupo A.P.D.A. no facebook.
you can try this functiion:
function extractFunctionBody(fn) {
var reg = /function \((.*)\)[ ]?{(.*)}$/g;
var match = reg.exec(fn.toString().replace(/\n/g, ";"));
if (match){
return match[2];
} else {
return "";
}
}
Try this:
/\{(\s*?.*?)*?\}/g.exec(test.toString())[0]
test.toString() will hold your entire declaration.
/{(\s*?.?)?}/g will match everything between your braces