diff options
Diffstat (limited to 'js/dojo-1.7.2/dojox/secure/sandbox.js')
| -rw-r--r-- | js/dojo-1.7.2/dojox/secure/sandbox.js | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/js/dojo-1.7.2/dojox/secure/sandbox.js b/js/dojo-1.7.2/dojox/secure/sandbox.js new file mode 100644 index 0000000..70cc782 --- /dev/null +++ b/js/dojo-1.7.2/dojox/secure/sandbox.js @@ -0,0 +1,348 @@ +//>>built +// wrapped by build app +define("dojox/secure/sandbox", ["dijit","dojo","dojox","dojo/require!dojox/secure/DOM,dojox/secure/capability,dojo/NodeList-fx,dojo/_base/url"], function(dijit,dojo,dojox){ +dojo.provide("dojox.secure.sandbox"); +dojo.require("dojox.secure.DOM"); +dojo.require("dojox.secure.capability"); +dojo.require("dojo.NodeList-fx"); +dojo.require("dojo._base.url"); + +(function() { + var oldTimeout = setTimeout; + var oldInterval = setInterval; + if({}.__proto__){ + // mozilla has unsafe methods on array + var fixMozArrayFunction = function (name) { + var method = Array.prototype[name]; + if(method && !method.fixed){ + (Array.prototype[name] = function () { + if (this == window) { + throw new TypeError("Called with wrong this"); + } + return method.apply(this, arguments); + }).fixed = true; + } + }; + // these are not safe in mozilla + fixMozArrayFunction('concat'); + fixMozArrayFunction('reverse'); + fixMozArrayFunction('sort'); + fixMozArrayFunction("slice"); + fixMozArrayFunction("forEach"); + fixMozArrayFunction("filter"); + fixMozArrayFunction("reduce"); + fixMozArrayFunction("reduceRight"); + fixMozArrayFunction("every"); + fixMozArrayFunction("map"); + fixMozArrayFunction("some"); + } + var xhrGet = function(){ + return dojo.xhrGet.apply(dojo,arguments); + }; + dojox.secure.sandbox = function(element) { + // summary: + // Creates a secure sandbox from which scripts and HTML can be loaded that + // will only be able to access the provided element and it's descendants, the + // rest of the DOM and JS environment will not be accessible to the sandboxed + // scripts and HTML. + // + // element: + // The DOM element to use as the container for the sandbox + // + // description: + // This function will create and return a sandbox object (see dojox.secure.__Sandbox) + // for the provided element. + var wrap = dojox.secure.DOM(element); + element = wrap(element); + var document = element.ownerDocument; + var mixin, dojo = dojox.secure._safeDojoFunctions(element,wrap); + var imports= []; + var safeCalls = ["isNaN","isFinite","parseInt","parseFloat","escape","unescape", + "encodeURI","encodeURIComponent","decodeURI","decodeURIComponent", + "alert","confirm","prompt", // some people may not want to allow these to be called, but they don't break capability-limiting + "Error","EvalError","RangeError","ReferenceError","SyntaxError","TypeError", + "Date","RegExp","Number","Object","Array","String","Math", + //"ADSAFE", // not using ADSAFE runtime for the time being + "setTimeout","setInterval","clearTimeout","clearInterval", // we make these safe below + "dojo","get","set","forEach","load","evaluate"]; + for(var i in dojo){ + safeCalls.push(i); // add the safe dojo functions to as available global top level functions + imports.push("var " + i + "=dojo." + i); // add to the list of imports + } + // open the dojo namespace (namespaces are pretty silly in an environment where you can't set globals) + eval(imports.join(";")); + function get(obj,prop) { + // basic access by index function + prop = '' + prop; + if(dojox.secure.badProps.test(prop)) { + throw new Error("bad property access"); + } + if(obj.__get__) { + return obj.__get__(prop); + } + return obj[prop]; + } + function set(obj,prop,value) { + // basic set by index function + prop = '' + prop; + get(obj,prop); // test it + if(obj.__set) { + return obj.__set(prop); + } + obj[prop] = value; + return value; + } + function forEach(obj,fun) { + // short syntax iterator function + if(typeof fun != "function"){ + throw new TypeError(); + } + if("length" in obj) { + // do arrays the fast way + if(obj.__get__) { + // use the catch getter + var len = obj.__get__('length'); + for (var i = 0; i < len; i++) { + if(i in obj) { + fun.call(obj, obj.__get__(i), i, obj); + } + } + } + else { + // fast + len = obj.length; + for (i = 0; i < len; i++) { + if(i in obj) { + fun.call(obj, obj[i], i, obj); + } + } + } + } + else { + // for each an object + for (i in obj) { + fun.call(obj, get(obj,i), i, obj); + } + } + } + function Class(/*Function*/superclass, /*Object*/properties, /*Object*/classProperties) { + // summary: + // A safe class constructor + // + // superclass: + // There may be zero or more superclass arguments. The constructed class + // will inherit from any provided superclasses, protypically from the first, + // via mixin for the subsequent. Later arguments + // will override properties/methods from earlier arguments + // + // properties: + // The constructed + // "class" will also have the methods/properties defined in this argument. + // These methods may utilize the <em>this</em> operator, and they + // are only the code that has access to <em>this</em>. Inner functions + // are also prohibited from using <em>this</em>. + // + // If no superclasses are provided, this object will be the prototype of the + // constructed class (no copying + // will be done). Consequently you can "beget" by calling new (Class(obj)). + // All methods are "bound", each call results in |this| safety checking call. + // + // classProperties: + // This properties will be copied to the new class function. + // + // Note that neither dojo.declare nor dojo.extend are acceptable class constructors as + // they are completely unsecure. This class constructor is conceptually based on declare + // but also somewhat influenced by base2, prototype, YUI, resig's patterns, etc. + // + // example: + // | var Car = Class({drive:function(speed) { ... } ); // create a Car class with a "drive" method + // | var FastCar = Class(Car,{driveFast: function(speed) { return this.drive(2 * speed); } }); // create a FastCar that extends Car + // | var fastCar = new FastCar; // instantiate + // | fastCar.driveFast(50); // call a method + // | var driveFast = fastCar.driveFast; + // | var driveFast(50); // this will throw an error, the method can be used with an object that is not an instance of FastCar + var proto,superConstructor,ourConstructor; + var arg; + for (var i = 0, l = arguments.length; typeof (arg = arguments[i]) == 'function' && i < l; i++) { + // go through each superclass argument + if(proto) { // we have a prototype now, we must mixin now + mixin(proto,arg.prototype); + } + else { + // this is the first argument, so we can define the prototype ourselves + // link up the prototype chain to the superclass's prototype, so we are a subtype + superConstructor = arg; + var F = function() {}; + F.prototype = arg.prototype; + proto = new F; + } + } + + if(arg) { // the next object should be the properties + // apply binding checking on all the functions + for (var j in arg) { + // TODO: check on non-enumerables? + var value = arg[j]; + if(typeof value == 'function') { + arg[j] = function() { + if(this instanceof Class){ + return arguments.callee.__rawMethod__.apply(this,arguments); + } + throw new Error("Method called on wrong object"); + }; + arg[j].__rawMethod__ = value; // may want to use this for reconstruction and toString,valueOf + } + } + if(arg.hasOwnProperty('constructor')) { + ourConstructor = arg.constructor; + } + } + proto = proto ? mixin(proto,arg) : arg; // if there is no proto yet, we can use the provided object + function Class() { + // the super class may not have been constructed using the same technique, we will just call the constructor + if(superConstructor){ + superConstructor.apply(this,arguments); + } + if(ourConstructor){ + ourConstructor.apply(this,arguments); + } + } + mixin(Class,arguments[i]); // the optional second object adds properties to the class + proto.constructor = Class; + Class.prototype = proto; + return Class; + } + function checkString(func){ + if(typeof func != 'function') { + throw new Error("String is not allowed in setTimeout/setInterval"); + } + } + function setTimeout(func,time) { + // sandboxed setTimeout + checkString(func); + return oldTimeout(func,time); + } + function setInterval(func,time) { + // sandboxed setInterval + checkString(func); + return oldInterval(func,time); + } + function evaluate(script){ + // sandboxed eval + return wrap.evaluate(script); + } + var load = wrap.load = function(url){ + // provides a loader function for the sandbox + if (url.match(/^[\w\s]*:/)){ + throw new Error("Access denied to cross-site requests"); + } + return xhrGet({url:(new dojo._Url(wrap.rootUrl,url))+'',secure:true}); + } + wrap.evaluate = function(script){ + //if(!alreadyValidated) { + dojox.secure.capability.validate(script,safeCalls, // the safe dojo library and standard operators + {document:1,element:1}); // these are secured DOM starting points + + //} + if(script.match(/^\s*[\[\{]/)) { + var result = eval('(' + script + ')'); + // TODO: call render on result? + } + else { + eval(script); + } + //eval('wrap.evaluate=('+arguments.callee.toString()+')'); // yeah, recursive scoping; + }; + return /*===== dojo.declare("dojox.secure.__Sandbox", null, =====*/ { // dojox.secure.__Sandbox + loadJS : function(url){ + // summary: + // Loads the script from the given URL using XHR (assuming + // a plugin system is in place for cross-site requests) within the sandbox + // + // url: + // The url of the script to load + wrap.rootUrl = url; + return xhrGet({url:url,secure:true}).addCallback(function(result) { + evaluate(result,element /*If we get the results with a secure proxy, we would call put true here */); + }); + }, + loadHTML : function(url){ + // summary: + // Loads the web page from the provided URL using XHR (assuming the + // plugin system is in place) within the sandbox. All scripts within the web + // page will also be sandboxed. + // + // url: + // The url of the web page to load + + wrap.rootUrl = url; + return xhrGet({url:url,secure:true}).addCallback(function(result){ + element.innerHTML = result; + }); + }, + evaluate : function(script){ + // summary: + // Evaluates the given script within the sandbox + // + // script: + // The JavaScript text to evaluate + return wrap.evaluate(script); + } + // TODO: could add something for pre-validated scripts + }/*===== ) =====*/; + }; +})(); +dojox.secure._safeDojoFunctions = function(element,wrap) { + // Creates a safe subset of Dojo core library + var safeFunctions = ["mixin","require","isString","isArray","isFunction","isObject","isArrayLike","isAlien", + "hitch","delegate","partial","trim","disconnect","subscribe","unsubscribe","Deferred","toJson","style","attr"]; + //var domFunctions = ["clone","byId"]; + var doc = element.ownerDocument; + var unwrap = dojox.secure.unwrap; + dojo.NodeList.prototype.addContent.safetyCheck = function(content){ + wrap.safeHTML(content); + }; + dojo.NodeList.prototype.style.safetyCheck = function(name,value){ + if(name=='behavior'){ + throw new Error("Can not set behavior"); + } + wrap.safeCSS(value); + }; + dojo.NodeList.prototype.attr.safetyCheck = function(name,value){ + if (value && (name == 'src' || name == 'href' || name=='style')){ + throw new Error("Illegal to set " + name); + } + }; + var safe = { + query : function(query,root) { + return wrap(dojo.query(query,unwrap(root || element))); // wrap the NodeList + }, + connect: function(el,event) { + var obj = el; + arguments[0] = unwrap(el); + if(obj!=arguments[0] && event.substring(0,2) != 'on'){ + // it is probably an element, and it doesn't look like an event handler, probably not safe + throw new Error("Invalid event name for element"); + } + return dojo.connect.apply(dojo,arguments); + }, + body : function() { + return element; + }, + byId : function(id) { + return element.ownerDocument.getElementById(id); // use the safe document + }, + fromJson : function(str) { + // make sure it is safe before passing it to the unsafe dojo.fromJson + dojox.secure.capability.validate(str,[],{}); + return dojo.fromJson(str); + } + }; + for (var i = 0; i < safeFunctions.length; i++) { + safe[safeFunctions[i]] = dojo[safeFunctions[i]]; + } + return safe; +}; + + +}); |
