1

Quite simply, I'd like to "re-hydrate" functions which are passed from AJAX, as follows:

//AJAX response:
{"foo":"bar","baz":"function(){console.log('I am back working as a function!');}"}

And obviously, baz should be a function and not a string. How would I do this?

Oliver Williams
  • 5,966
  • 7
  • 36
  • 78
  • 2
    Possible duplicate of [Is there a way to create a function from a string with javascript?](https://stackoverflow.com/questions/7650071/is-there-a-way-to-create-a-function-from-a-string-with-javascript) – Yonatan Vainer Sep 29 '18 at 20:02
  • check here: https://stackoverflow.com/questions/7650071/is-there-a-way-to-create-a-function-from-a-string-with-javascript – Yonatan Vainer Sep 29 '18 at 20:03

2 Answers2

2

As Jozef already suggested you can use eval().

But, if you go through Google you will see that the use of that function is NOT recommended:

  1. https://javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval/
  2. When is JavaScript's eval() not evil?
  3. https://javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval/
  4. Why is using the JavaScript eval function a bad idea?

As this blog suggests (http://2ality.com/2014/01/eval.html) I would recommend you, to use this:

let json = {"foo":"bar","baz":"function(){console.log('I am back working as a function!');}"};

let func = new Function("console.log('I am back working as a function!');");
func();

If you don't have the possibility to change your json you can simply use str.replace().


Please keep in mind that arbitrary code could be executed! I would strongly recommend that you do e.g. sth. like this instead of just responding with a function. By doing the following you would do some sort of whitelisting. So, no matter if the http-response has been manipulated, the attacker can only execute the pre-defined javascript functions.

function func1() {
  console.log('I am back working as a function!');
}

function func2() {
  console.log('another code block');
}

let json = {"foo":"bar","baz":"1"};

switch(json.baz) {
  case "1": func1();break;
  case "2": func2();break;
  default: console.error("Invalid response");
}

I hope this helps.

wsdt
  • 95
  • 1
  • 8
1

It's possible, but of course we must use the evil eval .. use at your own risk!!

var ajaxResponse = {"foo":"bar","baz":"function(){console.log('I am back working as a function!')}", "lambda": "() => console.log('Hello i\\'m a lambda')"};

function isAFunction(v) {
    try {
        eval("var f = " + v);
        return typeof f === "function";
    } catch (e) {
        return false;
    }
}

var result = Object.entries(ajaxResponse).reduce((obj, [key,value]) => {
      if (isAFunction(value)) {
          eval("obj[key] = " + value);
      } else {
            obj[key] = value;
      }
      return obj;
      
}, {});

result.baz();
result.lambda();
Terry Lennox
  • 29,471
  • 5
  • 28
  • 40
  • 1
    that does work, and I presume it will also hydrate any Objects that are declared inside the function itself. I am only doing this in an environment with trusted interaction between the client and server – Oliver Williams Sep 29 '18 at 20:37
  • You might need to play about with the syntax, but yes, it should do that! – Terry Lennox Sep 29 '18 at 20:41