1

I have the following string named abc (which consists of javascript variables declarations):

var abc = `
    var exp = 'test';
    var test = 15;
    var test2 = "wow";
`;

I would like to get the value of exp, test, test2 from this string.

One of the methods that might work is:

eval(abc);

However this solution is not suitable in typescript for security purposes, what other methods would you recommend ( feel free to propose some npm libraries) ?

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
rossanmol
  • 1,633
  • 3
  • 17
  • 34
  • Where does the string come from? It matters. – T.J. Crowder Feb 17 '18 at 12:13
  • This variable comes from an http request from a affiliate project. – rossanmol Feb 17 '18 at 12:13
  • Other than ruling out `eval`, have you tried anything or done any research to solve the problem? With the quoted string, it's fairly trivial. – T.J. Crowder Feb 17 '18 at 12:13
  • 1
    *"This variable comes from an http request from an affiliate domain."* You don't trust them? – T.J. Crowder Feb 17 '18 at 12:14
  • since you are using node.js why don't you use the `vm` core module to execute the script in a sandboxed env – 0.sh Feb 17 '18 at 12:14
  • @Crowder, the code from affiliate domain is developed by same organisation however using `eval` might bring production problems in case of modifications. – rossanmol Feb 17 '18 at 12:15
  • @Crowder, also typing in typescript will complain for such solution. – rossanmol Feb 17 '18 at 12:15
  • 1
    @0.sh: From [the documentation](https://nodejs.org/api/vm.html): *"Note: The vm module is not a security mechanism. **Do not use it to run untrusted code.**"* *(their emphasis)* – T.J. Crowder Feb 17 '18 at 12:16
  • 2
    @Coder: Typing issues can be solved. Either you trust them or you don't. If you do, `eval` is fine. If you don't, you'll have to do parsing (but if you don't trust them, why use data they give you?). So again: What have you tried? What research have you done? What attempt at solving the problem do you need help with? – T.J. Crowder Feb 17 '18 at 12:17
  • @T.J.Crowder I tried using regex, however I didn't manage to generate a regex which would actually match all 3 variables above. – rossanmol Feb 17 '18 at 12:18
  • @T.J.Crowder the problem is not the trust, it's the fact that the whole app is fully dependant on the eval function which is a black box. – rossanmol Feb 17 '18 at 12:21
  • 2
    @Coder: ??? `eval` is [very, very well-defined](https://tc39.github.io/ecma262/#sec-eval-x), not a black box. But that's fine, if you don't want to use `eval`, don't use `eval`. Try to solve the problem, and if you have a **specific** problem doing so, post a question about that problem. For instance: You say you've tried to solve it with regex (which is fine if and only if the code is as simple as shown). Great! It's quite easy to solve with regex. So show us what you tried and explain the trouble you're having with it. – T.J. Crowder Feb 17 '18 at 12:25

2 Answers2

0

Creating a function and passing the variable.

new Function has a closed scope in comparison to function eval.

var abc = `
    var exp = 'test';
    var test = 15;
    var test2 = "wow";
`;

var fn = (variable) => (new Function('', `${abc} return ${variable};`))();

console.log(fn('exp'));
console.log(fn('test'));
console.log(fn('test2'));
Ele
  • 33,468
  • 7
  • 37
  • 75
  • 1
    `new Function` is no different from `eval` in terms of the concerns the OP has raised with `eval`. – T.J. Crowder Feb 17 '18 at 12:42
  • 1
    @T.J.Crowder you're wrong because `new Function` has a closed scope. [Are eval() and new Function() the same thing?](https://stackoverflow.com/questions/4599857/are-eval-and-new-function-the-same-thing) – Ele Feb 17 '18 at 12:44
  • 2
    I didn't say they were the same. I said `new Function` has the same issues that the OP has raised with `eval`. See the comments on the question for details. – T.J. Crowder Feb 17 '18 at 12:50
  • If you want to do the OP's work for them, just give them a regex solution. It's trivial. – T.J. Crowder Feb 17 '18 at 12:53
  • @T.J.Crowder I know that regex would work. But this approach it’s different that eval regarding to security concerns. – Ele Feb 17 '18 at 12:56
  • 1
    No, it isn't. It still allows arbitrary code execution. The only difference between `eval` and `new Function` is that the former has access to in-scope non-global variables and the latter doesn't. That doesn't, remotely, mean you can use it to run untrusted code. And in any case, one of the OP's complaints is around *types* in TypeScript, which this does nothing to address. – T.J. Crowder Feb 17 '18 at 12:59
  • Well, I respect your opinion, however I can’t share it. Have a good day! – Ele Feb 17 '18 at 13:01
0

One way to do that would be the following: First we find the declarations by splitting the string using ; as delimiter

Now after we have found the declarations we use map() to extract the values of each one and return it into a new array.To find the value of a declaration we split it into 2 parts using '='.The first part is the declaration name and the second part is the declaration value

var abc = `var exp = 'test';
    var test = 15;
    var test2 = "wow";`;
//Trim string
abc = abc.trim();
//Split by ';'
var declarations = abc.split(';');
//The last item is empty so we remove it
declarations.pop();
console.log(declarations)
//Now that we have the declarations we need to get the values
//so we split each declaration using '='
var values = declarations.map(function(dec){
  var value = dec.split("=").pop()
  return value;
  
});


//Bonus
//This gets all declarations from a string and returns them as a key value object
function getDeclarations(s) {
    
    var variables = s.split(";");
    //Last variable is an empty string so pop it
    variables.pop()
    var declarations = {};
    variables.forEach(function (variable) {
        variable = variable.trim()
        var name = variable.split("=")[0].split("var")[1];
        var value = variable.split("=").pop();
        name = name.trim();
        value = value.trim();
        declarations[name] = value;
    });
    return declarations;
}
console.log(values)

console.log(getDeclarations(abc))
Manos Kounelakis
  • 2,848
  • 5
  • 31
  • 55