a:8:{s:9:"#provides";s:23:"dojox.secure.capability";s:9:"#resource";s:20:"secure/capability.js";s:23:"dojox.secure.capability";a:2:{s:4:"type";s:6:"Object";s:7:"summary";s:0:"";}s:32:"dojox.secure.capability.keywords";a:1:{s:7:"summary";s:0:"";}s:32:"dojox.secure.capability.validate";a:5:{s:4:"type";s:8:"Function";s:10:"parameters";a:3:{s:6:"script";a:2:{s:4:"type";s:6:"string";s:7:"summary";s:21:"the script to execute";}s:13:"safeLibraries";a:2:{s:4:"type";s:5:"Array";s:7:"summary";s:115:"The safe libraries that can be called (the functions can not be access/modified by the untrusted code, only called)";}s:11:"safeGlobals";a:2:{s:4:"type";s:6:"Object";s:7:"summary";s:65:"These globals can be freely interacted with by the untrusted code";}}s:6:"source";s:5025:"		var keywords = this.keywords;
		for (var i = 0; i < keywords.length; i++) {
			safeGlobals[keywords[i]]=true;
		}
		var badThis = "|this| keyword in object literal without a Class call";
		var blocks = []; // keeps track of the outer references from each inner block
		if(script.match(/[\u200c-\u200f\u202a-\u202e\u206a-\u206f\uff00-\uffff]/)){
			throw new Error("Illegal unicode characters detected");
		}
		if(script.match(/\/\*@cc_on/)){
			throw new Error("Conditional compilation token is not allowed");
		}
		script = script.replace(/\\["'\\\/bfnrtu]/g, '@'). // borrows some tricks from json.js
			// now clear line comments, block comments, regular expressions, and strings.
			// By doing it all at once, the regular expression uses left to right parsing, and the most
			// left token is read first. It is also more compact.
			replace(/\/\/.*|\/\*[\w\W]*?\*\/|\/(\\[\/\\]|[^*\/])(\\.|[^\/\n\\])*\/[gim]*|("[^"]*")|('[^']*')/g,function(t) {
				return t.match(/^\/\/|^\/\*/) ? ' ' : '0'; // comments are replaced with a space, strings and regex are replaced with a single safe token (0)
			}).
			replace(/\.\s*([a-z\$_A-Z][\w\$_]*)|([;,{])\s*([a-z\$_A-Z][\w\$_]*\s*):/g,function(t,prop,prefix,key) { 
				// find all the dot property references, all the object literal keys, and labels
				prop = prop || key; 
				if(/^__|^(apply|call|callee|caller|constructor|eval|prototype|this|unwatch|valueOf|watch)$|__$/.test(prop)){
					throw new Error("Illegal property name " + prop);
				}
				return (prefix && (prefix + "0:")) || '~'; // replace literal keys with 0: and replace properties with the innocuous ~
			});
		script.replace(/([^\[][\]\}]\s*=)|((\Wreturn|\S)\s*\[\s*\+?)|([^=!][=!]=[^=])/g,function(oper) {// check for illegal operator usages
			if(!oper.match(/((\Wreturn|[=\&\|\:\?\,])\s*\[)|\[\s*\+$/)){ // the whitelist for [ operator for array initializer context or [+num] syntax
				throw new Error("Illegal operator " + oper.substring(1));
			}
		});
		script = script.replace(new RegExp("(" + safeLibraries.join("|") + ")[\\s~]*\\(","g"),function(call) { // find library calls and make them look safe
			return "new("; // turn into a known safe call 
		});
		function findOuterRefs(block,func) {
			var outerRefs = {};
			block.replace(/#\d/g,function(b) { // graft in the outer references from the inner scopes
				var refs = blocks[b.substring(1)];
				for (var i in refs) {
					if(i == badThis) {
						throw i;
					}
					if(i == 'this' && refs[':method'] && refs['this'] == 1) {
						// if we are in an object literal the function may be a bindable method, this must only be in the local scope
						i = badThis;
					}
					if(i != ':method'){
						outerRefs[i] = 2; // the reference is more than just local
					}
				}
			});
			block.replace(/(\W|^)([a-z_\$A-Z][\w_\$]*)/g,function(t,a,identifier) { // find all the identifiers
				if(identifier.charAt(0)=='_'){
					throw new Error("Names may not start with _");
				}
				outerRefs[identifier] = 1;
			});
			return outerRefs;
		}	
		var newScript,outerRefs;
		function parseBlock(t,func,a,b,params,block) {
			block.replace(/(^|,)0:\s*function#(\d)/g,function(t,a,b) { // find functions in object literals
			// note that if named functions are allowed, it could be possible to have label: function name() {} which is a security breach
					var refs = blocks[b]; 
					refs[':method'] = 1;//mark it as a method
			});
			block = block.replace(/(^|[^_\w\$])Class\s*\(\s*([_\w\$]+\s*,\s*)*#(\d)/g,function(t,p,a,b) { // find Class calls
					var refs = blocks[b];
					delete refs[badThis];
					return (p||'') + (a||'') + "#" + b;
			});
			outerRefs = findOuterRefs(block,func); // find the variables in this block
			function parseVars(t,a,b,decl) { // find var decls
				decl.replace(/,?([a-z\$A-Z][_\w\$]*)/g,function(t,identifier) {
					if(identifier == 'Class'){
						throw new Error("Class is reserved");
					}
					delete outerRefs[identifier]; // outer reference is safely referenced here
				});
			}

			
			if(func) {
				parseVars(t,a,a,params); // the parameters are declare variables
			}
			block.replace(/(\W|^)(var) ([ \t,_\w\$]+)/g,parseVars); // and vars declare variables
			// FIXME: Give named functions #name syntax so they can be detected as vars in outer scopes (but be careful of nesting)
			return (a || '') + (b || '') + "#" + (blocks.push(outerRefs)-1); // return a block reference so the outer block can fetch it 
		}	
		do {
			// get all the blocks, starting with inside and moving out, capturing the parameters of functions and catchs as variables along the way
			newScript = script.replace(/((function|catch)(\s+[_\w\$]+)?\s*\(([^\)]*)\)\s*)?{([^{}]*)}/g, parseBlock); 
		}
		while(newScript != script && (script = newScript)); // keep going until we can't find anymore blocks
		parseBlock(0,0,0,0,0,script); //findOuterRefs(script); // find the references in the outside scope
		for (i in outerRefs) {
			if(!(i in safeGlobals)) {
				throw new Error("Illegal reference to " + i);
			}
		}";s:7:"summary";s:507:"pass in the text of a script. If it passes and it can be eval'ed, it should be safe.
Note that this does not do full syntax checking, it relies on eval to reject invalid scripts.
There are also known false rejections:
Nesting vars inside blocks will not declare the variable for the outer block
Named functions are not treated as declaration so they are generally not allowed unless the name is declared with a var.
Var declaration that involve multiple comma delimited variable assignments are not accepted";s:7:"returns";s:363:"comments are replaced with a space, strings and regex are replaced with a single safe token (0)|replace literal keys with 0: and replace properties with the innocuous ~|check for illegal operator usages|the whitelist for [ operator for array initializer context or [+num] syntax|turn into a known safe call|return a block reference so the outer block can fetch it";}s:21:"dojox.secure.badProps";a:1:{s:7:"summary";s:0:"";}s:12:"dojox.secure";a:2:{s:4:"type";s:6:"Object";s:7:"summary";s:0:"";}s:5:"dojox";a:2:{s:4:"type";s:6:"Object";s:7:"summary";s:0:"";}}