3

I'm still very new to JavaScript (not to coding though), so feel free to nit-pick and moron-map things for me.

I've attempted to create something that will accept user input. If the first character is an exclamation point, it'll attempt to create an object with that name and run the "action" method of that object. Else it'll treat it like regular text (for now an alert)

<script type="text/javascript">
function GetInput(input){

    // Trim the spaces off the beginning and end
    input = input.trim();

    if(input.charAt(0) != "!"){
        // Just some normal text
        alert(input);

        return true;
    }

/* Cut off the exclamation point, replace multiple spaces with one,
 * and get the arguments if any. args[0] = the command. */

    var args = input.substr(1).replace(/\s{2,}/g, " ").split(" ");

// Make sure the function is an object with a method named "action"
    if(eval("typeof "+args[0]+";") === "function"
        && eval("typeof "+args[0]+".prototype.action;") === "function"){

        eval("var command = new "+args[0]+"();");

        command.action(args);
    }else{
        alert('"'+args[0]+'" is not a command.');
    }

    return true;
}
</script>

The only problem I'm noticing with this so far is the eval statements. I know I could use a switch/case and ditch eval all together, or even make an array containing the names of the allowed functions and compare the input with that array prior to eval, but I'm sure there's got to be a better way.

I just want to be able to make the object and method and not update anything (which I believe is one of the major uses of of duck-typing?). Is this possible without eval? If not, is there an easy way to sanitize input for strings to avoid things like "!eval(alert('u b haxed'))" or "!a;alert('u b haxed')"?

Thanks in advance

1

1 Answer 1

3

You should use eval only once to get the function, then do everything with it in a variable.

var args = input.substr(1).split(/\s+/);
var fn = eval(args[0]);
if (typeof fn == 'function' && typeof fn.prototype.action == 'function') {
    var command = new fn();
    command.action(args);
} else {
    alert('"'+args[0]+'" could not be evaluated to a valid command.');
}

return true;

If those constructors are global variables, you also can access them as a property of the window object:

var fn = window[ args[0] ];
Sign up to request clarification or add additional context in comments.

7 Comments

Shouldn't use eval even once as args[0] comes from user input. windows[args[0]] is much safer.
Between this answer and TwiNight's comment I got exactly what I needed. Thank you two so much.
@TwiNight: Not in general, as every user could manually execute malicious code in his own browser. window[args[0]] won't have any side effects, but is more restricted. Depends on what the user needs and how experienced he is.
True, but eval is generally depreciated.
@TwiNight eval is nowhere near deprecated. The only problem with eval is that by inexperienced users it's often misused and abused. There are many scenario's where using eval is perfectly acceptable, and no security risks are imposed. Deprecated means that they actually want to remove the feature from the language, but for backward compatibility they keep it around. However there's a good chance they will remove it in a future version. This is not the case with eval.
|