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.

8
  • There's no HTML anywhere in the code you posted. Commented Feb 15, 2016 at 19:22
  • 1
    Why do you say "html string" instead of "js code string"? Commented Feb 15, 2016 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. Commented Feb 15, 2016 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. Commented Feb 15, 2016 at 19:29
  • @Bergi i have edited the question. mistake with words. Commented Feb 15, 2016 at 19:31

2 Answers 2

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");
Sign up to request clarification or add additional context in comments.

1 Comment

You shouldn't call that object global when it's just a namespace. Otherwise, +1
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
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.