Javascript - eval object creation? - javascript

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

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] ];

Related

A "safe place" to eval trusted code in Javascript (with specific context)? [Edit: how can you break it?]

Don't judge me yet on the title, I know eval is evil, but there are reasons I do it that way, and it will be very limited. Here is the thing: I want to create a safe space where i can run specific (and trusted) bits of code, and retrieve the result (if it fits to what i expect). For security reasons, I wanted to cut it from all other scopes (this space is asked for the result, and is supposed not to be able to export anything to surrounding scopes by itself).
I came to a solution which seems to work, that also can add a context to the execution, but i'm not sure if it is valid, or if there are security breaches in this system. Can you please tell me if there is something wrong with it?
It actually creates local vars with same name as the global ones, to prevent accessing to them. It also strips functions (I will add feature to preserve the ones I want to keep). The function is declared closest from globals as possible, to avoid visibility of local scopes that would be higher (a parameter to remove these specific local vars is planned).
function contextNoScope(root, context) {
//I had to pass window as parameter for it to work properly
for(var key in root){
if(key != '0' && key != 'window'){
eval('var ' + key + '=undefined;');
}
}
var window = undefined;
var root = undefined; //root has to be forbidden too
return function() {
this.eval = function(str){ return eval(str); };
return this;
}.call(context);
}
USAGE:
(function(root){
function contextNoScope(root, context) {
//...same as previous
}
var context = { x: 3 };
var space = contextNoScope(root, context);
console.log(space.eval('this.x + 1'));
})(window);
(NOTE: if you test this code in a global way, don't forget to add a special fix if you pass a global var for the context, because it will be masked like all the others. A fix has to be added also if you want try to pass window as the context parameter, for obvious reasons..)
EDIT:
To make things clearer about what the scripts do and what can solve my problem: I assume there is no total safety in JS with what can be called 'trusted source', as we are obviously talking here about importing scripts. By trusted I mean that the script origin will be checked, and security keys added, to begin with.
Each script takes a certain variable from the given context and adds a property to it. The names here are given, meaning that we know beforehand which var will be modified and what is the name and type of the property added to it. In a way I can already check if what is done was intended or not, the problem here is to be "sure" that any code won't be able to interfere with events or the DOM mostly, and doesn't remove or modify anything in the given context except adding the propery..
EDIT 2: please break it!
(I'm not yet specialist of all the site rules, correct me if it's not the way to properly edit: i chose not to modify the first code and add the new version, even if it gets a bit long.)
I am heading for a proper sandbox for my solution, made by better people than me, but because I am curious and want to keep learning, I post here an improved version of what i did, because I'd like to know how this still can be broken. So i am now looking for precise tricks that can break this system:
function contextNoScope(context) {
var len, i, keys, val, window = root, isNaN = root.isNaN, console = root.console;
if(!context){ context = {}; }
keys = Object.getOwnPropertyNames(window);
if(len = keys.length){
for(i = 0; i < len; i++){
val = keys[i];
//TODO: remove 'console' from the if (debug purpose)
if(isNaN(val) && val != 'window' && val != 'eval' && val != 'isNaN' && val != 'console'){
eval('var ' + val + '=undefined;');
}
}
}
isNaN = undefined;
len = undefined;
i = undefined;
keys = undefined;
val = undefined;
eval('var root = undefined');
return function() {
this.eval = function(str){
if(str){
str = str.toString();
//TODO: replace by more relevant regex (it currently throws error for words like 'evaluation')
if(str.indexOf('constructor') > -1 || str.indexOf('__proto__') > -1 || str.indexOf('prototype') > -1 || str.indexOf('eval') > -1){
console.log('ERROR - str contains forbidden code "constructor", "__proto__", "eval", "prototype"', '\n' + str);
return false;
}
try{
eval(str);
return true;
}catch(e){
console.log(e + '\nin:\n' + str);
return false;
}
}
console.log('ERROR - str is not defined: ', str);
return false;
};
return this;
}.call(context);
}
Some explanations for the changes:
In the first version i added window as a parameter because of a basic mistake about when the word var is evaluated, it is not necessary. But passing window as another name ('root' here) seems easier. The whole function is wrapped the same way as in the first version usage.
added getOwnPropertyNames to get also the non-enumerable properties, but I know about the backwards compatibility issue, that is not what I mean by 'break the system' to use an older browser (I know it already)
added masking of the function local parameters or variables
the test for isNaN(val) is here to not evaluate as a variable the numbers-properties of window, that reference the i-frames
eval('var root = undefined'); is a trick for the var to be created at the moment the line is executed, not at the very beginning, like it would be with a regular var
I am aware that functions declared in this space don't access regular functions anymore (try with an alert(1), it won't work)
Anything that's based on setting variables to shadow globals can be broken by Function.apply(undefined), which runs a function with this set to the global context. For instance:
(function() {
this.alert(1);
}).apply(undefined);
Anything that's based on regular expressions can probably be broken by some combination of:
Escaping
new Function, eval, etc
Constructing strings using non-alphanumeric Javascript expressions
Bottom line: You cannot build an effective sandbox out of Javascript. It's been tried; every attempt has been complicated, fragile, and eventually broken.

Passing parameters to new() in Javascript

I'm starting to play around with Node.js and specifically with the LessCSS compiler. I saw this call on the source code of the lessc script:
new(less.Parser) ({
paths: [path.dirname(input)].concat(options.paths),
optimization: options.optimization,
filename: input,
strictImports: options.strictImports,
dumpLineNumbers: options.dumpLineNumbers
}).parse(data, function (err, tree) {
//...
});
What I don't understand is how that new(lessParser)({}) call works.
From what I've been reading about Object-oriented Javascript I only found examples of new being called like so: object = new Someting
So the questions are: how does new work in that case? Is it calling less.Parser as the constructor? Also, what are the parenthesis (following the new call) executing/returning?
Thanks!
The code you posted is exactly technically (or more or less) the same as doing
var parserOptions = {
paths: [path.dirname(input)].concat(options.paths),
optimization: options.optimization,
filename: input,
strictImports: options.strictImports,
dumpLineNumbers: options.dumpLineNumbers
};
var parser = new less.Parser(parserOptions);
parser.parse(data, function (err, tree) {
//...
});
But with a few shortcuts and with some parenthesis in "unconventional" places.
JavaScript is a loose type language and it is interpreted in tokens. Which means that it is not too limiting on it's syntax, as long as the grammar is respected.
This let things like :
var a = false;
var b = function() { };
var c = false;
new(a || b || c)();
be completely valid, and will create a new instance of b as it is the first one non-false value defined after the tested variable a. (Note that it does not check if b is actually a function. If b was non-false and not a function, the JS engine would throw that it is not a function at run-time.)
Just a comment really.
The expression new(less.Parser)({…}) is identical to new less.Parser({…}).
The parenthesis are a grouping operator that says "evaluate this expression as a single expression". It is common to use that syntax when the expression in the parenthesis would return a different result without the parenthesis, e.g.
var x, y = 7;
alert( typeof (x || y)) // "number"
alert( typeof x || y ) // "undefined"
But since they make no difference to the outcome in the OP, they are pointless and possibly harmful as they change a well known pattern into one that might appear to some as if new can be called as a function.

Get function name in JavaScript

Does anyone know if there is a way to get JavaScript function name. For example I got a function like
function test1(){
alert(1);
}
I have it in my head section. Then I create an object obj1 and put my function there
obj1.func = test1;
When I call a method in obj1 object, do I have any way to get my function name (test1) inside of this method, except parsing the source (this.func.toString()) of the function.
function test() { alert(arguments.callee.name); }
b = test;
b();
outputs "test" (in Chrome, Firefox and probably Safari). However, arguments.callee.name is only available from inside the function.
If you want to get name from outside you may parse it out of:
b.toString();
but I think name property of function object might be what you need:
alert(b.name);
this however does not seem work for IE and Opera so you are left with parsing it out manually in those browsers.
Until ES2015, there was no standard way to get the name of a function. Most current browsers support a name property on Function objects that was non-standard until ES2015, but no current version of IE does. The only option this leaves you if you need to support IE is trying to parse the name from the function's string representation, which is not a good idea. There's a (long) discussion here about it: http://groups.google.com/group/comp.lang.javascript/browse_frm/thread/b85dfb2f2006c9f0
The best thing to do is:
function functionName(fun) {
var ret = fun.toString();
ret = ret.substr('function '.length);
ret = ret.substr(0, ret.indexOf('('));
return ret;
}
Note: Using Function.caller is non-standard and arguments.callee is forbidden in strict mode.
Here's what I use to put class names in error messages. It includes code to get the name of functions, which works in most browsers.
Obviously, there is no standard way that always works, so you should always provide a name that can be used if no other name is found.
var nameFromToStringRegex = /^function\s?([^\s(]*)/;
/**
* Gets the classname of an object or function if it can. Otherwise returns the provided default.
*
* Getting the name of a function is not a standard feature, so while this will work in many
* cases, it should not be relied upon except for informational messages (e.g. logging and Error
* messages).
*
* #private
*/
function className(object, defaultName) {
var result = "";
if (typeof object === 'function') {
result = object.name || object.toString().match(nameFromToStringRegex)[1];
} else if (typeof object.constructor === 'function') {
result = className(object.constructor, defaultName);
}
return result || defaultName;
}
This is probably the best way to do it:
var myfunc = function () {};
var funcName = myfunc.constructor.name;
This can be done outside the execution of the function, and you can check within the context of the browser console.
Happy coding!
One interesting way I'm experimenting with is a declaration like the following:
var test1 = function test1(){
alert(1);
};
It's a little hacky, but what ends up happening is test1 is a local variable that holds a [Function: test1] object.
Here's what happens when you use code based on it:
test1(); //runs the function as expected
console.log(test1.name); //prints 'test1'
So if you do the following:
obj1.func = test1;
You'll then be able to reference obj1.func.name and it'll return 'test1'.
You could convert your function into a string (fn + '') and split it later at whitespace and open bracket /\s|\(/.
var getFunctionName = function (fn) {
return (fn + '').split(/\s|\(/)[1];
};

Know if a variable is a native object in javascript

is there a way to know if a variable passed into a function is a native object? I mean, i have a function that requires only native objects as arguments, for every other type of variable it throws an error. So:
func(Array); //works
func(String); //works
func(Date); //works
func(Object); //works
...
func([]); //Throwr error
func({}); //Throws error
I want to know if there's a way to distinguish between native objects and everything else.
You'd have to do an === (or !==) against the list of accepted values (which wouldn't be that long, from your question), being aware that that could be tricked into thinking something wasn't a native that was (just from another window).
But basically:
if (obj !== Array &&
obj !== String &&
obj !== Date &&
/* ...and so on, there are only a few of them... */
) {
throw "your error";
}
Edit Re my comment about things from other windows: Be aware that constructors from one window are not === to constructors from another window (including iframes), e.g.:
var wnd = window.open('blank.html');
alert("wnd.Array === Array? " + (wnd.Array === Array));
alerts "wnd.Array === Array? false", because the Array in wnd is not the same as the Array in your current window, even though both are built-in constructors for arrays.
As far as I know, current "best practice" way to get the type of something is
var theType = Object.prototype.toString.call(theObject);
That'll give you a string that looks like "[object Array]".
Now, keep in mind that [] is an Array instance, and {} is an Object instance.
There's a "typeof" operator in JavaScript that might help.
alert (typeof arg)
The other (a little more sophisticated) approach is to use
arg.prototype.constructor
this will give the reference to a function that was used to construct the object

How best to determine if an argument is not sent to the JavaScript function

I have now seen 2 methods for determining if an argument has been passed to a JavaScript function. I'm wondering if one method is better than the other or if one is just bad to use?
function Test(argument1, argument2) {
if (Test.arguments.length == 1) argument2 = 'blah';
alert(argument2);
}
Test('test');
Or
function Test(argument1, argument2) {
argument2 = argument2 || 'blah';
alert(argument2);
}
Test('test');
As far as I can tell, they both result in the same thing, but I've only used the first one before in production.
Another Option as mentioned by Tom:
function Test(argument1, argument2) {
if(argument2 === null) {
argument2 = 'blah';
}
alert(argument2);
}
As per Juan's comment, it would be better to change Tom's suggestion to:
function Test(argument1, argument2) {
if(argument2 === undefined) {
argument2 = 'blah';
}
alert(argument2);
}
There are several different ways to check if an argument was passed to a function. In addition to the two you mentioned in your (original) question - checking arguments.length or using the || operator to provide default values - one can also explicitly check the arguments for undefined via argument2 === undefined or typeof argument2 === 'undefined' if one is paranoid (see comments).
Using the || operator has become standard practice - all the cool kids do it - but be careful: The default value will be triggered if the argument evaluates to false, which means it might actually be undefined, null, false, 0, '' (or anything else for which Boolean(...) returns false).
So the question is when to use which check, as they all yield slightly different results.
Checking arguments.length exhibits the 'most correct' behaviour, but it might not be feasible if there's more than one optional argument.
The test for undefined is next 'best' - it only 'fails' if the function is explicitly called with an undefined value, which in all likelyhood should be treated the same way as omitting the argument.
The use of the || operator might trigger usage of the default value even if a valid argument is provided. On the other hand, its behaviour might actually be desired.
To summarize: Only use it if you know what you're doing!
In my opinion, using || is also the way to go if there's more than one optional argument and one doesn't want to pass an object literal as a workaround for named parameters.
Another nice way to provide default values using arguments.length is possible by falling through the labels of a switch statement:
function test(requiredArg, optionalArg1, optionalArg2, optionalArg3) {
switch(arguments.length) {
case 1: optionalArg1 = 'default1';
case 2: optionalArg2 = 'default2';
case 3: optionalArg3 = 'default3';
case 4: break;
default: throw new Error('illegal argument count')
}
// do stuff
}
This has the downside that the programmer's intention is not (visually) obvious and uses 'magic numbers'; it is therefore possibly error prone.
If you are using jQuery, one option that is nice (especially for complicated situations) is to use jQuery's extend method.
function foo(options) {
default_options = {
timeout : 1000,
callback : function(){},
some_number : 50,
some_text : "hello world"
};
options = $.extend({}, default_options, options);
}
If you call the function then like this:
foo({timeout : 500});
The options variable would then be:
{
timeout : 500,
callback : function(){},
some_number : 50,
some_text : "hello world"
};
This is one of the few cases where I find the test:
if(! argument2) {
}
works quite nicely and carries the correct implication syntactically.
(With the simultaneous restriction that I wouldn't allow a legitimate null value for argument2 which has some other meaning; but that would be really confusing.)
EDIT:
This is a really good example of a stylistic difference between loosely-typed and strongly-typed languages; and a stylistic option that javascript affords in spades.
My personal preference (with no criticism meant for other preferences) is minimalism. The less the code has to say, as long as I'm consistent and concise, the less someone else has to comprehend to correctly infer my meaning.
One implication of that preference is that I don't want to - don't find it useful to - pile up a bunch of type-dependency tests. Instead, I try to make the code mean what it looks like it means; and test only for what I really will need to test for.
One of the aggravations I find in some other peoples' code is needing to figure out whether or not they expect, in the larger context, to actually run into the cases they are testing for. Or if they are trying to test for everything possible, on the chance that they don't anticipate the context completely enough. Which means I end up needing to track them down exhaustively in both directions before I can confidently refactor or modify anything. I figure that there's a good chance they might have put those various tests in place because they foresaw circumstances where they would be needed (and which usually aren't apparent to me).
(I consider that a serious downside in the way these folks use dynamic languages. Too often people don't want to give up all the static tests, and end up faking it.)
I've seen this most glaringly in comparing comprehensive ActionScript 3 code with elegant javascript code. The AS3 can be 3 or 4 times the bulk of the js, and the reliability I suspect is at least no better, just because of the number (3-4X) of coding decisions that were made.
As you say, Shog9, YMMV. :D
In ES6 (ES2015) you can use Default parameters
function Test(arg1 = 'Hello', arg2 = 'World!'){
alert(arg1 + ' ' +arg2);
}
Test('Hello', 'World!'); // Hello World!
Test('Hello'); // Hello World!
Test(); // Hello World!
url = url === undefined ? location.href : url;
There are significant differences. Let's set up some test cases:
var unused; // value will be undefined
Test("test1", "some value");
Test("test2");
Test("test3", unused);
Test("test4", null);
Test("test5", 0);
Test("test6", "");
With the first method you describe, only the second test will use the default value. The second method will default all but the first (as JS will convert undefined, null, 0, and "" into the boolean false. And if you were to use Tom's method, only the fourth test will use the default!
Which method you choose really depends on your intended behavior. If values other than undefined are allowable for argument2, then you'll probably want some variation on the first; if a non-zero, non-null, non-empty value is desired, then the second method is ideal - indeed, it is often used to quickly eliminate such a wide range of values from consideration.
I'm sorry, I still yet cant comment, so to answer Tom's answer...
In javascript (undefined != null) == false
In fact that function wont work with "null", you should use "undefined"
There is a tricky way as well to find, whether a parameter is passed to a function or not. Have a look at the below example:
this.setCurrent = function(value) {
this.current = value || 0;
};
This necessary means that if the value of value is not present/passed - set it to 0.
Pretty cool huh!
Why not using the !! operator? This operator, placed before the variable, turn it to a boolean (if I've understood well), so !!undefined and !!null (and even !!NaN, which can be quite interesting) will return false.
Here is an exemple:
function foo(bar){
console.log(!!bar);
}
foo("hey") //=> will log true
foo() //=> will log false
Sometimes you want undefined as a possible argument but you still have situations where the argument may not be passed. In that case you can use arguments.length to check how many arguments were passed.
// Throw error if the field is not matching our expectations
function testField(label, fieldValue, expectedValue) {
console.log(arguments) // Gives: [Arguments] { '0': 'id', '1': 1, '2': undefined }
if(arguments.length === 2) {
if(!fieldValue) {
throw new Error(`Field "${label}" must have a value`)
}
}
else if(expectedValue === undefined) {
if(fieldValue !== undefined) {
throw Error(`Field "${label}" must NOT have a value`)
}
}
// We stringify so our check works for objects as well
else {
if(JSON.stringify(fieldValue) !== JSON.stringify(expectedValue)) {
throw Error(`Field "${label}" must equal ${expectedValue} but was ${fieldValue}`)
}
}
}
testField('id', 12) -> Passes, we don't want id to be blank
testField('id', undefined, undefined) -> Passes, we want id to be undefined
testField('id', 12, undefined) -> Errors, we wanted id to be undefined
It can be convenient to approach argument detection by evoking your function with an Object of optional properties:
function foo(options) {
var config = { // defaults
list: 'string value',
of: [a, b, c],
optional: {x: y},
objects: function(param){
// do stuff here
}
};
if(options !== undefined){
for (i in config) {
if (config.hasOwnProperty(i)){
if (options[i] !== undefined) { config[i] = options[i]; }
}
}
}
}
Some times you may also want to check for type, specially if you are using the function as getter and setter. The following code is ES6 (will not run in EcmaScript 5 or older):
class PrivateTest {
constructor(aNumber) {
let _aNumber = aNumber;
//Privileged setter/getter with access to private _number:
this.aNumber = function(value) {
if (value !== undefined && (typeof value === typeof _aNumber)) {
_aNumber = value;
}
else {
return _aNumber;
}
}
}
}
function example(arg) {
var argumentID = '0'; //1,2,3,4...whatever
if (argumentID in arguments === false) {
console.log(`the argument with id ${argumentID} was not passed to the function`);
}
}
Because arrays inherit from Object.prototype. Consider ⇑ to make the world better.
fnCalledFunction(Param1,Param2, window.YourOptionalParameter)
If above function is called from many places and you are sure first 2 parameters are passed from every where but not sure about 3rd parameter then you can use window.
window.param3 will handle if it is not defined from the caller method.

Categories

Resources