0

I am writing code to generate thumbnails based on user selected image manipulation actions which may be multiple as choosen by user using lwip npm package module.

For multiple actions lwip provides batch function and then chaining other manipulating functions.The problem i faced is that user may select any combination of host of manipulating functions and it is too cumbersome to check for each and every combinations of selected actions.

So, i have generated the code dynamically as js code string which i need to execute as function without using eval that may compromise application security

Below is my code

    'use strict';
(function(uploadhandler){

    var lwip=require('lwip'),
        imageSettingProvider=require('../data/imagesettingprovider'),
        uploadFolder='public/uploads/',
        imageManipulatorHelper=require('./imagemanipulationactions'),
        manipulatedImage='';

    uploadhandler.generateThumbnail=function(filePath,filename,ImageUploadSetting,fs){
        // compound effects
        var thumbnailPath='';

        lwip.open(filePath, function(err, image) {
            if (err) {
                console.log(err);
            }else{
                imageSettingProvider.getImageSetting(ImageUploadSetting,{},function(err,imageSettings){
                    imageSettings.forEach(function(element,index,array){
                        thumbnailPath=uploadFolder + element.folderName + '/' + filename;
                        var imageAction=element.action;
                        if(imageAction.indexOf(',')>-1){
                            var imageManipulationActions=imageAction.split(',');
                            var manipulationHtml='';
                            manipulationHtml += 'image.batch()';
                            var actionHtml='';
                            imageManipulationActions.forEach(function(actionelement,actionindex,actionarray){
                                actionHtml += uploadhandler.PerformMultipleImageManipulation(actionelement,element,actionHtml);
                            });
                            manipulationHtml += actionHtml;
                            console.log('----------------------------------------------------------------------------------------------------------');
                            manipulationHtml += '.writeFile(thumbnailPath, function(err) { if (err) throw err;});';
                            console.log(manipulationHtml);

                        }
                    });
                });
            }
        });
    };


    uploadhandler.PerformMultipleImageManipulation=function(imageAction,imageOpts,actionHtml){
        switch (imageAction){
            case "crop":
                actionHtml = '.crop(' + imageOpts.width + ',' + imageOpts.height + ')';
                break;
            case "cropbycoordinates":
                actionHtml = '.crop(' + imageOpts.cropLeftPos + ',' + imageOpts.cropTopPos + ',' + imageOpts.cropRightPos + ',' + imageOpts.cropBottomPos + ')';
                break;
            case "resize":
                actionHtml = '.resize(' + imageOpts.width + ',' + imageOpts.height + ')';
                break;
            case "resizecrop":
                actionHtml = '.resize(' + imageOpts.width + ',' + imageOpts.height + ')' + '.crop(' + imageOpts.width + ',' + imageOpts.height + ')';
                break;
            case "rotate":
                actionHtml = '.rotate(' + imageOpts.rotateDegree + ',' + imageOpts.backgroundColor + ')';
                break;
            case "blur":
                actionHtml = '.blur(' + imageOpts.blurVal + ')';
                break;
            case "scale":
                actionHtml = '.scale(' + imageOpts.scaleVal + ')';
                break;
            case "mirror":
                actionHtml = '.mirror(' + imageOpts.flipAxes + ')';
                break;
            case "fade":
                actionHtml = '.fade(' + imageOpts.fadeVal + ')';
                break;
        }
        return actionHtml;
    };

})(module.exports);

Now when i log the manipulation variable to the console,it gives:

image.batch()
.resize(480,320)
.crop(480,320)
.rotate(75,white)
.writeFile(thumbnailPath, function(err) { 
if (err) throw err;
});

Now i need to execute this above js code string as function to generate thumbnail image without using javascript eval function.

I have tried using following approach from sitepoint website:

// function we want to run
var fnstring = "runMe";

// find object
var fn = window[fnstring];

// is object a function?
if (typeof fn === "function") fn();

But it gives me with the error " ReferenceError: window is not defined "

Please guide me to solve this problem.

shrawan_lakhe
  • 358
  • 2
  • 5
  • 22
  • There's no HTML anywhere in the code you posted. – Pointy Feb 15 '16 at 19:22
  • 1
    Why do you say "html string" instead of "js code string"? – Bergi Feb 15 '16 at 19:27
  • 1
    There is nothing wrong with `eval` if you want to execute dynamically-generated code. Certainly, all other solutions that execute code are just as insecure. – Bergi Feb 15 '16 at 19:27
  • "*The problem i faced is that user may select any combination of host of manipulating functions and it is too cumbersome to check for each and every combinations of selected actions.*" - that doesn't sound like a reason to generate code strings to me. – Bergi Feb 15 '16 at 19:29
  • @Bergi i have edited the question. mistake with words. – shrawan_lakhe Feb 15 '16 at 19:31
  • @Bergi user may select one or multiple from ['crop','cropbycoordinates','resize','cropresize','rotate','blur','scale','mirror','fade','border'] these actions for generating one thumbnail and to generate exact code to match user choice, i may have to check for each and every combination which may be too large. so i have to generate js code string...i would be very thankful if there is other better ways for it – shrawan_lakhe Feb 15 '16 at 19:33
  • @shrawan_lakhe: Yes, then fetch the method names of the selected actions from that array and dynamically invoke them on your batch object. No need for eval. – Bergi Feb 15 '16 at 19:35
  • Possible duplicate of [What is the node.js equivalent of window\["myvar"\] = value?](http://stackoverflow.com/questions/10984629/what-is-the-node-js-equivalent-of-windowmyvar-value) – Johannes Jander Feb 15 '16 at 19:36

2 Answers2

4

Fetch the actions into global object and execute each one using each particular function's namespace.

var helper = {};
helper.b = function() {
  console.log("foo");
}
helper.c = function() {
  console.log("bar");
}

//execute them

function execute(key) {
  try {
    helper[key]();
  } catch (e) {
    throw new Error("Function does not exist");
  }
}

execute("b");
execute("c");
execute("d");
vorillaz
  • 6,098
  • 2
  • 30
  • 46
0

If it helps, you could run a regex replace function.

Note: I have not tested this.

// if worried about security with eval, you may want to put functions in an object instead of using global
const myFunctions = {
    runMe: function(){/* do stuff */},
    runMe2: function(){/* do stuff */}
};

const allowedFuncs = ['runMe', 'runMe2'];
// or dynamic to entire object
const allowedFuncs = Object.keys(myFunctions);

str = str.replace(new RegExp('(''+allowedFuncs.join('|')+)\\((.*?)\\)', 'g'), (str, func, attrs) => {
    // check allowed list for added security
    if(allowedFuncs.includes(func)){
        attrs = attrs.split(',');
        myFunctions[func](...attrs); // 3 dots makes js expand array to params separated by camas
    }
    return str; // returning str replaces nothing
});
SwiftNinjaPro
  • 117
  • 1
  • 7