Reference error when trying to return a string Nodejs VM

511 Views Asked by At

I'm using a npm module called safe-eval to evaluate some JavaScript code i send to the backend. The code is usually a function that will be executed inside of the safe-eval with the parameters I'll provide. The problem is that when returning certain value, in this case a string, it's not doing so and instead it's giving my a Reference error and interpreting the string value as a variable.

router.post('/test/:nombre', function(req, res, next){  
    let nombEjer = req.params.nombre;
    let code = "";
    let error = {etype : ""}

    try{
        //Evalua el codigo de manera segura
        code = safeEval(req.body.code, {},{timeout: 5, displayErrors : true});
    }catch(e){
        error.linea = e.stack.split('evalmachine.<anonymous>:')[1].substring(1, 2);
        error.etype = e.toString();

        //Devulve error en caso de que mala sintaxis
        return res.status(400).send(error); 
    }

    //Si es una funcion, trae los valores y soluciones de la base de datos
    if(typeof code === "function"){ 
        let resultados = [];

        Ejercicios.findOne({titulo: nombEjer}, 'parametros', (err, doc)=>{
            if(err) return res.status(500).send({error : "No se ha podido encontrar el ejercicio"});

            //Ejecutar el codigo con cada lista de parametros y almacenar los resultados
            doc.parametros.forEach(function(elem, indx) {
                try{
                    resultados[indx] = safeEval(code(...elem));
                }catch(e){
                    error.etype = e.toString();
                }
            });

            if(error.etype != "") return res.status(400).send(error);
            return res.status(200).send({results : resultados});
        });
    }else{
        return res.status(400).send({etype: "El codigo es invalido"});
    }
});

The problem happens in one of the iterations of the forEach.

Yes, i know that forEach shouldn't be used as a control statement for a loop, but in this case I did it so to catch any error that could arise during the execution with the list of parameters that I'm passing by.

That said, the problem arises when I pass the list of parameters with this function (this function is supposed to return the string n times):

//Function I'm passing
function cadenaVeces(str, n) {
  return str.repeat(n);
}

//Parameter I'm passing
doc.parametros = [ [ "Ho", 2 ], [ "Ho", 3 ], [ "Ho", 1 ], [ "Ho", 0 ], [ "Ho", 5 ], [ "Vaya chico!", 2 ], [ "x", 4 ], [ "", 4 ], [ "codigo", 2 ], [ "codigo", 3 ] ]

This is the response I got.

{ "etype": "ReferenceError: codigocodigocodigo is not defined" }

1

There are 1 best solutions below

0
On BEST ANSWER

This behavior seems valid: safeEval takes a code string, evaluates it and returns some value: primitive or object (including function). When you call safeEval(req.body.code) it returns function code(). When you call safeEval(code(...elem));, for example safeEval(code(...[ "codigo", 3 ])); this is what happens:

  1. code(...[ "codigo", 3 ]) returns 'codigocodigocodigo';
  2. safeEval('codigocodigocodigo') tries to evaluate codigocodigocodigo as a code, not as a string, and reference error happens, as codigocodigocodigo is not declared.

If you need just a string, you can simply call code(...elem). If you need the result of the function to be evaluated as a string (which seems confusing though), call safeEval(`'${code(...elem)}'`); to enclose the result in quotes.