diff options
| -rw-r--r-- | eval_test.js | 532 | ||||
| -rw-r--r-- | main_background.js | 186 | ||||
| -rw-r--r-- | manifest.json | 2 | ||||
| -rw-r--r-- | test.html | 0 | ||||
| -rw-r--r-- | testtag.html | 17 | 
5 files changed, 73 insertions, 664 deletions
diff --git a/eval_test.js b/eval_test.js deleted file mode 100644 index f59aed2..0000000 --- a/eval_test.js +++ /dev/null @@ -1,532 +0,0 @@ - -/** -*	This file is the "skeleton" of the final system to determine -*	if a script is accepted or blocked. -* -*	Some assets taken from script_detector.js -* -*/ - -// the list of all available event attributes -var intrinsic_events = [ -    "onload", -    "onunload", -    "onclick", -    "ondblclick", -    "onmousedown", -    "onmouseup", -    "onmouseover", -    "onmousemove", -    "onmouseout", -    "onfocus", -    "onblur", -    "onkeypress", -    "onkeydown", -    "onkeyup", -    "onsubmit", -    "onreset", -    "onselect", -    "onchange" -]; -/* -	NONTRIVIAL THINGS: -	- Fetch -	- XMLhttpRequest -	- eval() -	- ? -	JAVASCRIPT CAN BE FOUND IN: -	- Event handlers (onclick, onload, onsubmit, etc.) -	- <script>JS</script> -	- <script src="/JS.js"></script> -	WAYS TO DETERMINE PASS/FAIL: -	- "// @license [magnet link] [identifier]" then "// @license-end" (may also use /* comments) -	- Automatic whitelist: (http://bzr.savannah.gnu.org/lh/librejs/dev/annotate/head:/data/script_libraries/script-libraries.json_ -	- <table id="jslicense-labels1"><table> which may be linked to by a link tag identified by rel="jslicense" or data-jslicense="1" -	- In the first script tag, declare the license with @licstart/@licend -*/ - -var licenses = { -	'Apache-2.0':{ -		'URL': 'http://www.apache.org/licenses/LICENSE-2.0', -		'Magnet link': 'magnet:?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7&dn=apache-2.0.txt' -	}, -	// No identifier was present in documentation -	'Artistic-2.0':{ -		'URL': 'http://www.perlfoundation.org/artistic_license_2_0', -		'Magnet link': 'magnet:?xt=urn:btih:54fd2283f9dbdf29466d2df1a98bf8f65cafe314&dn=artistic-2.0.txt' -	}, -	// No identifier was present in documentation -	'Boost':{ -		'URL': 'http://www.boost.org/LICENSE_1_0.txt', -		'Magnet link': 'magnet:?xt=urn:btih:89a97c535628232f2f3888c2b7b8ffd4c078cec0&dn=Boost-1.0.txt' -	}, -	// No identifier was present in documentation -	'BSD-3-Clause':{ -		'URL': 'http://opensource.org/licenses/BSD-3-Clause', -		'Magnet link': 'magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt', -	}, -	'CPAL-1.0':{ -		'URL': 'http://opensource.org/licenses/cpal_1.0', -		'Magnet link': 'magnet:?xt=urn:btih:84143bc45939fc8fa42921d619a95462c2031c5c&dn=cpal-1.0.txt' -	}, -	'CC0-1.0':{ -		'URL': 'http://creativecommons.org/publicdomain/zero/1.0/legalcode', -		'Magnet link': 'magnet:?xt=urn:btih:90dc5c0be029de84e523b9b3922520e79e0e6f08&dn=cc0.txt' -	}, -	'EPL-1.0':{ -		'URL': 'http://www.eclipse.org/legal/epl-v10.html', -		'Magnet link': 'magnet:?xt=urn:btih:4c6a2ad0018cd461e9b0fc44e1b340d2c1828b22&dn=epl-1.0.txt' -	}, -	'Expat':{ -		'URL': 'http://www.jclark.com/xml/copying.txt', -		'Magnet link': 'magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt' -	}, -	'FreeBSD':{ -		'URL': 'http://www.freebsd.org/copyright/freebsd-license.html', -		'Magnet link': 'magnet:?xt=urn:btih:87f119ba0b429ba17a44b4bffcab33165ebdacc0&dn=freebsd.txt' -	}, -	'GPL-2.0':{ -		'URL': 'http://www.gnu.org/licenses/gpl-2.0.html', -		'Magnet link': 'magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt' -	}, -	'GPL-3.0':{ -		'URL': 'http://www.gnu.org/licenses/gpl-3.0.html', -		'Magnet link': 'magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt' -	}, -	'LGPL-2.1':{ -		'URL': 'http://www.gnu.org/licenses/lgpl-2.1.html', -		'Magnet link': 'magnet:?xt=urn:btih:5de60da917303dbfad4f93fb1b985ced5a89eac2&dn=lgpl-2.1.txt' -	}, -	'LGPL-3.0':{ -		'URL': 'http://www.gnu.org/licenses/lgpl-3.0.html', -		'Magnet link': 'magnet:?xt=urn:btih:0ef1b8170b3b615170ff270def6427c317705f85&dn=lgpl-3.0.txt' -	}, -	'AGPL-3.0':{ -		'URL': 'http://www.gnu.org/licenses/agpl-3.0.html', -		'Magnet link': 'magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt' -	}, -	'ISC':{ -		'URL': 'https://www.isc.org/downloads/software-support-policy/isc-license/', -		'Magnet link': 'magnet:?xt=urn:btih:b8999bbaf509c08d127678643c515b9ab0836bae&dn=ISC.txt' -	}, -	'MPL-2.0':{ -		'URL': 'http://www.mozilla.org/MPL/2.0', -		'Magnet link': 'magnet:?xt=urn:btih:3877d6d54b3accd4bc32f8a48bf32ebc0901502a&dn=mpl-2.0.txt' -	}, -	// "Public domain is not a license" -	// Replace with CC0? -	'Public-Domain':{ -		'URL': 'https://www.gnu.org/licenses/license-list.html#PublicDomain', -		'Magnet link': 'magnet:?xt=urn:btih:e95b018ef3580986a04669f1b5879592219e2a7a&dn=public-domain.txt' -	}, -	'UPL-1.0': { -		'URL': 'https://oss.oracle.com/licenses/upl/', -		'Magnet link': 'magnet:?xt=urn:btih:478974f4d41c3fa84c4befba25f283527fad107d&dn=upl-1.0.txt' -	}, -	'WTFPL': { -		'URL': 'http://www.wtfpl.net/txt/copying/', -		'Magnet link': 'magnet:?xt=urn:btih:723febf9f6185544f57f0660a41489c7d6b4931b&dn=wtfpl.txt' -	}, -	'Unlicense':{ -		'URL': 'http://unlicense.org/UNLICENSE', -		'Magnet link': 'magnet:?xt=urn:btih:5ac446d35272cc2e4e85e4325b146d0b7ca8f50c&dn=unlicense.txt' -	}, -	// No identifier was present in documentation -	'X11':{ -		'URL': 'http://www.xfree86.org/3.3.6/COPYRIGHT2.html#3', -		'Magnet link': 'magnet:?xt=urn:btih:5305d91886084f776adcf57509a648432709a7c7&dn=x11.txt'	 -	}, -	// Picked one of the two links that were there -	'Modified-BSD':{ -		'URL': 'http://www.xfree86.org/current/LICENSE4.html', -		'Magnet link': 'magnet:?xt=urn:btih:12f2ec9e8de2a3b0002a33d518d6010cc8ab2ae9&dn=xfree86.txt' -	} -} - -// Objects which could be used to do nontrivial things -// Bracket suffix notation could still be exploited to get some of these objects  -var reserved_objects = [ -	"fetch", -	"XMLHttpRequest", -	"chrome", // only on chrome -	"browser", // only on firefox -	"eval" -]; - -function get_final_page(html_string, callback){ - -	/** -	*	Determines if a block of javascript is trivial or not. -	* -	*	true = trivial, false = nontrivial	 -	* -	*/ -	function evaluate(script,name){ -		function reserved_object_regex(object){ -			// Matches use of object as a variable	 -			 -			// This accounts for both unary, binary and assignment operators -			var arith_operators = "\\+\\-\\*\\/\\%\\="; -			 -			// These are allowed to preceed or trail a variable as in 'if(true){eval("thiscode")};' -			// However, if you have 'function(){eval}' where the "}" char trails "eval", this can't -			// be used to invoke member objects or pass arguments. -			var scope_chars = "\{\}\]\[\(\)\,"; -		 -			// No property accessors are allowed to follow the string stored in "object" -			// Whitespace is allowed to come between these property accessors  -			var trailing_chars = "\s*"+"\(\.\["; - -			return new RegExp("(?:[^\\w\\d]|^|(?:"+arith_operators+"))"+object+'(?:\\s*?(?:[\\;\\,\\.\\(\\[])\\s*?)',"g"); -		}		 -		reserved_object_regex("window"); -		// Strings -		var all_strings = new RegExp('".*?"'+"|'.*?'","gm"); -		// multi-line "/*" "*/" comments -		var ml_comment = /\/\*([\s\S]+?)\*\//g; -		// in-line "//" comments -		var il_comment = /\/\/.+/gm; -		// The contents of bracket pairs -		var bracket_pairs = /\[.+?\]/g; - -		// Replace string consts with values that won't interfere -		var temp = script.replace(/'.+?'+/gm,"'string'"); -		temp = temp.replace(/".+?"+/gm,'"string"'); -		// Remove comments -		temp = temp.replace(ml_comment,""); -		temp = temp.replace(il_comment,""); -		// Now that there can't be any brackets inside of comments or strings, -		//   - -		console.log("------evaluation results for "+ name +"------"); -		console.log("Script accesses reserved objects?"); -		var flag = true; -		for(var i = 0; i < reserved_objects.length; i++){ -			var res = reserved_object_regex(reserved_objects[i]).exec(script); -			if(res != null){ -				console.log("%c fail","color:red;"); -				console.log(res["input"].substr(res["index"]-15,res["index"]+15)); -				flag = false;		 -			} -		} -		if(flag){ -			console.log("%c pass","color:green;"); -		} - -		return flag; -	} - -	/** -	*	Looks at the output of the @license regex and determines if the -	*	license is good. -	*/ -	function license_valid(matches){ -		// Being overly careful with safety checks -		if(matches.length != 4){ -			return false; -		} -		if(matches[1] != "@license"){ -			return false;	 -		} -		if(licenses[matches[3]] === undefined){ -			return false; -		} -		if(licenses[matches[3]]["Magnet link"] != matches[2]){ -			return false; -		} -		return true; -	} -	/** -	* -	*	Runs regexes to search for explicit delcarations of script -	*	licenses on the argument.  -	*	It detects:	 -	*	//@license, //@license-end -	*	//licstart, //licend -	*	 -	*	We are assuming that the "stack depth" of @license tags can not exceed 1. -	*	If this isn't correct, we can make it recursive.  -	* -	*/ -	// TODO: Known bug: extra \n chars thrown in at some splices  -	function license_read(script_src,name){ -		if(typeof(script_src) != "string"){ -			return "fail" -		} -		// Contains only good Javascript -		var edited_src = ""; -		// Once Javascript has been "judged", remove it from here -		var unedited_src = script_src; -		var first = true; -		while(true){ -			if(first){ -				first = false; -				//console.log("input:"); -				//console.log("%c"+unedited_src,"color:#550000"); -			} -			var matches = /^(@license)\s([\S]+)\s([\S]+$)/gm.exec(unedited_src); -			if(matches == null){ -				//console.log("No more matches, almost done"); -				if(evaluate(unedited_src,name)){ -					edited_src += unedited_src; -				} -				return edited_src; -			} -			// operate on everything before the next match. -			//console.log("Everything before the next match"); -			var before = unedited_src.substr(0,matches["index"]); -			//console.log(before); -			if(evaluate(before,name)){ -				edited_src += before; -			} -			// This should remove the substring "before" -			unedited_src = unedited_src.substr(matches["index"],unedited_src.length); -			// find the end tag and check if it is valid -			matches_end = /^(@license-end)/gm.exec(unedited_src); -			if(matches_end == null){ -				console.log("ERROR: @license with no @license-end"); -				return [false,"ERROR: @license with no @license-end"]; -			} -			var endtag_end_index = matches_end["index"]+matches_end[0].length; -			// accept next tag if its license is good. -			if(license_valid(matches)){ -				edited_src =  edited_src + unedited_src.substr(0,endtag_end_index); -			} -			// Remove the next tag (it will be in edited_src if it was accepted) -			unedited_src = unedited_src.substr(endtag_end_index,unedited_src.length); -			//console.log("New input after iteration:");		 -			//console.log("%c"+unedited_src,"color:red;"); -			//console.log("Current output:"); -			//console.log("%c"+edited_src,"color:green;"); -		} -	} -	/** -	* -	*	Checks the whitelist in storage -	*	(Not the comma seperated whitelist from settings) -	* -	*/ -	function is_whitelisted(){ -		// TODO: implement when this is a background script -		return false; -	} - - -	/** -	*	Parses the weblabels table from a DOM object -	* -	*/ -	function read_weblabels_table(weblabel){ -		var data = {}; -		var tbody = weblabel.getElementsByTagName("td"); -		for(var i = 0; i < tbody.length; i++){ -			var link = tbody[i].getElementsByTagName("a")[0]; -			//console.log(link.href); -			if(link.innerText in licenses){ -				console.log("%cFree: " + link.innerText,"color:green;"); -				data[encodeURI(link.innerText)] = "free"; -			} else{ -				console.log("%cUnknown: " + link.innerText,"color:red;"); -				data[encodeURI(link.innerText)] = "unknown"; -			} -		} -		console.log("web labels table data:"); -		console.log(data); -		return data; -	} - -	/** -	*	Reads the weblabels table from a link. -	* -	*/ -	function get_table(html_doc, callback, url){ -		var xml = new XMLHttpRequest(); -		xml.open("get",url); -		xml.onload = function(){ -			var a = new DOMParser() -			var doc = a.parseFromString(this.responseText,"text/html"); -			var web_label = doc.getElementById("jslicense-labels1"); -			if(web_label != null){ -				read_w_table(html_doc, callback, table_data=read_weblabels_table(web_label)); -			} -		} -		xml.send(); -	} -	/** -	*	Basically an extension of "analyze"  -	* -	*	Calls license_read() on all the document's scripts. license_read() then returns an edited version -	*	according to license status and trivial/nontrivial status. -	* -	*	Added because I was having async issues	 -	*/ -	function read_w_table(html_doc, callback, table_data=false){ -		 -		var has_intrinsic_events = []; -		for(var i = 0; i < html_doc.all.length; i++){ -			for(var j = 0; j < intrinsicEvents.length; j++){ -				if(intrinsicEvents[j] in html_doc.all[i].attributes){ -					has_intrinsic_events.push([i,j]); -				} -			} -		} - -		var done = false; -		var amt_done = 0; -		var amt_remote_scripts = 0; -		var amt_todo = html_doc.scripts.length + has_intrinsic_events.length; - -		function check_done(){ -			console.log(amt_done + "/" + (amt_todo - amt_remote_scripts) ); -			if(amt_done > amt_todo){ -				console.warn("Not supposed to happen"); -			} -			if(done == false && amt_done >= (amt_todo - amt_remote_scripts) ){ -				console.log("%c DONE.","color:red;"); -				callback(html_doc); -				done = true; -				// TODO: Convert this to async -				// TODO: Call update_popup() here with reasons -			} -		} -		// "i" is an index in html_doc.scripts -		function edit_src(src, i, name){ -			var edited = license_read(src,name); -			if(edited == "string"){ -				html_doc.scripts[i].outerHTML = "<script name='librejs-accepted'>"+edited+"</script>"; -			} else{ -				html_doc.scripts[i].outerHTML = "<script name='librejs-denied'>"+name+"</script>"; -			} -			amt_done++; -		} -		// "i" is an index in html_doc.all -		// "j" is an index in intrinsicEvents -		function edit_event(src,i,j,name){ -			var edited = license_read(src,name); - -			if(edited == "string"){ -				html_doc.all[i].attributes[intrinsicEvents[j]].value = edited; -			} else{ -				html_doc.all[i].attributes[intrinsicEvents[j]].value = "//Denied by LibreJS"; -			} -			amt_done++; -		} - -		for(var i = 0; i < html_doc.scripts.length; i++){ -			// convert between relative link and file name (table_data indexes by file name) -			var tok_index = html_doc.scripts[i].src.split("/").length; -			var scriptname = html_doc.scripts[i].src.split("/")[tok_index-1]; - -			if(table_data != false && scriptname in table_data){ -				console.log("script contained in weblabel data."); -				if(table_data[scriptname] == "free"){ -					console.log("script is free"); -					continue; -				} - -				console.log("script is unknown");		 -			} - -			if(html_doc.scripts[i].src != ""){ -				// this is a remote script ("<script src='script.js'></script>") -				var name = html_doc.scripts[i].src; -				console.log("%c Will evaluate script '" + name + "' when it arrives. Document.scripts index: "+i,"color:blue;");	 -				amt_remote_scripts++; - -			} else{ -				// it is an inline script ("<script>console.log('test');</script>") -				console.log("%c Evaluating inline script. Document.scripts index: "+i,"color:blue;"); -				//console.log(html_doc.scripts[i].innerText); -				edit_src(html_doc.scripts[i].innerText, i, "src: inline (index "+i+")"); -			}	 -		} -		// Find all the document's elements with intrinsic events -		for(var i = 0; i < has_intrinsic_events.length; i++){ -			var s_name = "html_doc.all["+has_intrinsic_events[i][0]+"]"; -			edit_event(html_doc.all[has_intrinsic_events[i][0]].attributes[intrinsicEvents[has_intrinsic_events[i][1]]].value,has_intrinsic_events[i][0],has_intrinsic_events[i][1],s_name); -		} - -		check_done(); - -	} -	/* -	*	Basically just calls license_read() on all the Javascript in html_source -	*/ -	function analyze(html_source,callback){ -		// TODO: Call get_whitelisted_status on this page's URL - -		var parser = new DOMParser(); -		var html_doc = parser.parseFromString(html_source, "text/html"); - -		// Test "the first piece of Javascript available to the page" for the license comment -		var finished = false; -		if(html_doc.scripts[0] !== undefined){ -			if(html_doc.scripts[0].src != ""){ -				// this function is here because otherwise there would be async issues -				function get_first_js(){ -					var name = html_doc.scripts[0].src; -					var xml = new XMLHttpRequest(); -					xml.open("get", html_doc.scripts[0].src); -					xml.onload = function(response){ -						var matches = this.responseText.match(/@licstart[\s\S]+@licend/g); -						if(matches != null){ -							console.log("License comment found:"); -							console.log(matches[0]); -							console.log("Trusting that the entire page is freely licensed."); -							callback(true); -						} -					} -					xml.send(); -				} -				get_first_js(); -			} else{ -				console.log("%c Script " + i + ": (src: inline)","color:red;"); -				var matches = html_doc.scripts[0].innerText.match(/@licstart[\s\S]+@licend/g); -				if(matches != null){ -					console.log("License comment found:"); -					console.log(matches[0]); -					console.log("Trusting that the entire page is freely licensed."); -					callback(true); -				} -			}	 -		} - -		var table_data = {}; -		var found_table_flag = false; -		// Test for the link that has rel="jslicense", data-jslicense="1"   -		for(var i = 0; i < html_doc.links.length; i++){ -			// TODO: also check if data-jslicense == "1". (how?) -			if(html_doc.links[i].rel == "jslicense"){ -				console.log("Found HTML table link:"); -				get_table(html_doc, callback, html_doc.links[i].href);			 -				found_table_flag = true;			 -				break; -			} -		} -		// Test for the JavaScript Web Labels table on this page -		var weblabel = html_doc.getElementById("jslicense-labels1"); -		if(weblabel !== undefined && weblabel != null && found_table_flag == false){ -			console.log("Found web labels table"); -			read_w_table(html_doc, callback, table_data=read_weblabels_table(weblabel)); -		}  -		if(found_table_flag == false){ -			read_w_table(html_doc, callback); -		} -	} - -	analyze(html_string,callback); - -} - -get_final_page(document.documentElement.outerHTML,function(a){ -	console.log("returned"); -	if(typeof(a) == "boolean"){ -		return; -	} -	document.documentElement.innerHTML = a.documentElement.innerHTML; -}); - - - - - diff --git a/main_background.js b/main_background.js index c4a2b7c..b91eeca 100644 --- a/main_background.js +++ b/main_background.js @@ -1,43 +1,15 @@ +var acorn = require('acorn'); +var jssha = require('jssha'); - -/* - A JavaScript implementation of the SHA family of hashes, as - defined in FIPS PUB 180-4 and FIPS PUB 202, as well as the corresponding - HMAC implementation as defined in FIPS PUB 198a - Copyright Brian Turek 2008-2017 - Distributed under the BSD License - See http://caligatio.github.com/jsSHA/ for more information - Several functions taken from Paul Johnston -*/ - -'use strict';(function(I){function w(c,a,d){var l=0,b=[],g=0,f,n,k,e,h,q,y,p,m=!1,t=[],r=[],u,z=!1;d=d||{};f=d.encoding||"UTF8";u=d.numRounds||1;if(u!==parseInt(u,10)||1>u)throw Error("numRounds must a integer >= 1");if(0===c.lastIndexOf("SHA-",0))if(q=function(b,a){return A(b,a,c)},y=function(b,a,l,f){var g,e;if("SHA-224"===c||"SHA-256"===c)g=(a+65>>>9<<4)+15,e=16;else throw Error("Unexpected error in SHA-2 implementation");for(;b.length<=g;)b.push(0);b[a>>>5]|=128<<24-a%32;a=a+l;b[g]=a&4294967295; -b[g-1]=a/4294967296|0;l=b.length;for(a=0;a<l;a+=e)f=A(b.slice(a,a+e),f,c);if("SHA-224"===c)b=[f[0],f[1],f[2],f[3],f[4],f[5],f[6]];else if("SHA-256"===c)b=f;else throw Error("Unexpected error in SHA-2 implementation");return b},p=function(b){return b.slice()},"SHA-224"===c)h=512,e=224;else if("SHA-256"===c)h=512,e=256;else throw Error("Chosen SHA variant is not supported");else throw Error("Chosen SHA variant is not supported");k=B(a,f);n=x(c);this.setHMACKey=function(b,a,g){var e;if(!0===m)throw Error("HMAC key already set"); -if(!0===z)throw Error("Cannot set HMAC key after calling update");f=(g||{}).encoding||"UTF8";a=B(a,f)(b);b=a.binLen;a=a.value;e=h>>>3;g=e/4-1;if(e<b/8){for(a=y(a,b,0,x(c));a.length<=g;)a.push(0);a[g]&=4294967040}else if(e>b/8){for(;a.length<=g;)a.push(0);a[g]&=4294967040}for(b=0;b<=g;b+=1)t[b]=a[b]^909522486,r[b]=a[b]^1549556828;n=q(t,n);l=h;m=!0};this.update=function(a){var c,f,e,d=0,p=h>>>5;c=k(a,b,g);a=c.binLen;f=c.value;c=a>>>5;for(e=0;e<c;e+=p)d+h<=a&&(n=q(f.slice(e,e+p),n),d+=h);l+=d;b=f.slice(d>>> -5);g=a%h;z=!0};this.getHash=function(a,f){var d,h,k,q;if(!0===m)throw Error("Cannot call getHash after setting HMAC key");k=C(f);switch(a){case "HEX":d=function(a){return D(a,e,k)};break;case "B64":d=function(a){return E(a,e,k)};break;case "BYTES":d=function(a){return F(a,e)};break;case "ARRAYBUFFER":try{h=new ArrayBuffer(0)}catch(v){throw Error("ARRAYBUFFER not supported by this environment");}d=function(a){return G(a,e)};break;default:throw Error("format must be HEX, B64, BYTES, or ARRAYBUFFER"); -}q=y(b.slice(),g,l,p(n));for(h=1;h<u;h+=1)q=y(q,e,0,x(c));return d(q)};this.getHMAC=function(a,f){var d,k,t,u;if(!1===m)throw Error("Cannot call getHMAC without first setting HMAC key");t=C(f);switch(a){case "HEX":d=function(a){return D(a,e,t)};break;case "B64":d=function(a){return E(a,e,t)};break;case "BYTES":d=function(a){return F(a,e)};break;case "ARRAYBUFFER":try{d=new ArrayBuffer(0)}catch(v){throw Error("ARRAYBUFFER not supported by this environment");}d=function(a){return G(a,e)};break;default:throw Error("outputFormat must be HEX, B64, BYTES, or ARRAYBUFFER"); -}k=y(b.slice(),g,l,p(n));u=q(r,x(c));u=y(k,e,h,u);return d(u)}}function m(){}function D(c,a,d){var l="";a/=8;var b,g;for(b=0;b<a;b+=1)g=c[b>>>2]>>>8*(3+b%4*-1),l+="0123456789abcdef".charAt(g>>>4&15)+"0123456789abcdef".charAt(g&15);return d.outputUpper?l.toUpperCase():l}function E(c,a,d){var l="",b=a/8,g,f,n;for(g=0;g<b;g+=3)for(f=g+1<b?c[g+1>>>2]:0,n=g+2<b?c[g+2>>>2]:0,n=(c[g>>>2]>>>8*(3+g%4*-1)&255)<<16|(f>>>8*(3+(g+1)%4*-1)&255)<<8|n>>>8*(3+(g+2)%4*-1)&255,f=0;4>f;f+=1)8*g+6*f<=a?l+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(n>>> -6*(3-f)&63):l+=d.b64Pad;return l}function F(c,a){var d="",l=a/8,b,g;for(b=0;b<l;b+=1)g=c[b>>>2]>>>8*(3+b%4*-1)&255,d+=String.fromCharCode(g);return d}function G(c,a){var d=a/8,l,b=new ArrayBuffer(d),g;g=new Uint8Array(b);for(l=0;l<d;l+=1)g[l]=c[l>>>2]>>>8*(3+l%4*-1)&255;return b}function C(c){var a={outputUpper:!1,b64Pad:"=",shakeLen:-1};c=c||{};a.outputUpper=c.outputUpper||!1;!0===c.hasOwnProperty("b64Pad")&&(a.b64Pad=c.b64Pad);if("boolean"!==typeof a.outputUpper)throw Error("Invalid outputUpper formatting option"); -if("string"!==typeof a.b64Pad)throw Error("Invalid b64Pad formatting option");return a}function B(c,a){var d;switch(a){case "UTF8":case "UTF16BE":case "UTF16LE":break;default:throw Error("encoding must be UTF8, UTF16BE, or UTF16LE");}switch(c){case "HEX":d=function(a,b,c){var f=a.length,d,k,e,h,q;if(0!==f%2)throw Error("String of HEX type must be in byte increments");b=b||[0];c=c||0;q=c>>>3;for(d=0;d<f;d+=2){k=parseInt(a.substr(d,2),16);if(isNaN(k))throw Error("String of HEX type contains invalid characters"); -h=(d>>>1)+q;for(e=h>>>2;b.length<=e;)b.push(0);b[e]|=k<<8*(3+h%4*-1)}return{value:b,binLen:4*f+c}};break;case "TEXT":d=function(c,b,d){var f,n,k=0,e,h,q,m,p,r;b=b||[0];d=d||0;q=d>>>3;if("UTF8"===a)for(r=3,e=0;e<c.length;e+=1)for(f=c.charCodeAt(e),n=[],128>f?n.push(f):2048>f?(n.push(192|f>>>6),n.push(128|f&63)):55296>f||57344<=f?n.push(224|f>>>12,128|f>>>6&63,128|f&63):(e+=1,f=65536+((f&1023)<<10|c.charCodeAt(e)&1023),n.push(240|f>>>18,128|f>>>12&63,128|f>>>6&63,128|f&63)),h=0;h<n.length;h+=1){p=k+ -q;for(m=p>>>2;b.length<=m;)b.push(0);b[m]|=n[h]<<8*(r+p%4*-1);k+=1}else if("UTF16BE"===a||"UTF16LE"===a)for(r=2,n="UTF16LE"===a&&!0||"UTF16LE"!==a&&!1,e=0;e<c.length;e+=1){f=c.charCodeAt(e);!0===n&&(h=f&255,f=h<<8|f>>>8);p=k+q;for(m=p>>>2;b.length<=m;)b.push(0);b[m]|=f<<8*(r+p%4*-1);k+=2}return{value:b,binLen:8*k+d}};break;case "B64":d=function(a,b,c){var f=0,d,k,e,h,q,m,p;if(-1===a.search(/^[a-zA-Z0-9=+\/]+$/))throw Error("Invalid character in base-64 string");k=a.indexOf("=");a=a.replace(/\=/g, -"");if(-1!==k&&k<a.length)throw Error("Invalid '=' found in base-64 string");b=b||[0];c=c||0;m=c>>>3;for(k=0;k<a.length;k+=4){q=a.substr(k,4);for(e=h=0;e<q.length;e+=1)d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(q[e]),h|=d<<18-6*e;for(e=0;e<q.length-1;e+=1){p=f+m;for(d=p>>>2;b.length<=d;)b.push(0);b[d]|=(h>>>16-8*e&255)<<8*(3+p%4*-1);f+=1}}return{value:b,binLen:8*f+c}};break;case "BYTES":d=function(a,b,c){var d,n,k,e,h;b=b||[0];c=c||0;k=c>>>3;for(n=0;n<a.length;n+= -1)d=a.charCodeAt(n),h=n+k,e=h>>>2,b.length<=e&&b.push(0),b[e]|=d<<8*(3+h%4*-1);return{value:b,binLen:8*a.length+c}};break;case "ARRAYBUFFER":try{d=new ArrayBuffer(0)}catch(l){throw Error("ARRAYBUFFER not supported by this environment");}d=function(a,b,c){var d,n,k,e,h;b=b||[0];c=c||0;n=c>>>3;h=new Uint8Array(a);for(d=0;d<a.byteLength;d+=1)e=d+n,k=e>>>2,b.length<=k&&b.push(0),b[k]|=h[d]<<8*(3+e%4*-1);return{value:b,binLen:8*a.byteLength+c}};break;default:throw Error("format must be HEX, TEXT, B64, BYTES, or ARRAYBUFFER"); -}return d}function r(c,a){return c>>>a|c<<32-a}function J(c,a,d){return c&a^~c&d}function K(c,a,d){return c&a^c&d^a&d}function L(c){return r(c,2)^r(c,13)^r(c,22)}function M(c){return r(c,6)^r(c,11)^r(c,25)}function N(c){return r(c,7)^r(c,18)^c>>>3}function O(c){return r(c,17)^r(c,19)^c>>>10}function P(c,a){var d=(c&65535)+(a&65535);return((c>>>16)+(a>>>16)+(d>>>16)&65535)<<16|d&65535}function Q(c,a,d,l){var b=(c&65535)+(a&65535)+(d&65535)+(l&65535);return((c>>>16)+(a>>>16)+(d>>>16)+(l>>>16)+(b>>> -16)&65535)<<16|b&65535}function R(c,a,d,l,b){var g=(c&65535)+(a&65535)+(d&65535)+(l&65535)+(b&65535);return((c>>>16)+(a>>>16)+(d>>>16)+(l>>>16)+(b>>>16)+(g>>>16)&65535)<<16|g&65535}function x(c){var a=[],d;if(0===c.lastIndexOf("SHA-",0))switch(a=[3238371032,914150663,812702999,4144912697,4290775857,1750603025,1694076839,3204075428],d=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225],c){case "SHA-224":break;case "SHA-256":a=d;break;case "SHA-384":a=[new m,new m, -new m,new m,new m,new m,new m,new m];break;case "SHA-512":a=[new m,new m,new m,new m,new m,new m,new m,new m];break;default:throw Error("Unknown SHA variant");}else throw Error("No SHA variants supported");return a}function A(c,a,d){var l,b,g,f,n,k,e,h,m,r,p,w,t,x,u,z,A,B,C,D,E,F,v=[],G;if("SHA-224"===d||"SHA-256"===d)r=64,w=1,F=Number,t=P,x=Q,u=R,z=N,A=O,B=L,C=M,E=K,D=J,G=H;else throw Error("Unexpected error in SHA-2 implementation");d=a[0];l=a[1];b=a[2];g=a[3];f=a[4];n=a[5];k=a[6];e=a[7];for(p= -0;p<r;p+=1)16>p?(m=p*w,h=c.length<=m?0:c[m],m=c.length<=m+1?0:c[m+1],v[p]=new F(h,m)):v[p]=x(A(v[p-2]),v[p-7],z(v[p-15]),v[p-16]),h=u(e,C(f),D(f,n,k),G[p],v[p]),m=t(B(d),E(d,l,b)),e=k,k=n,n=f,f=t(g,h),g=b,b=l,l=d,d=t(h,m);a[0]=t(d,a[0]);a[1]=t(l,a[1]);a[2]=t(b,a[2]);a[3]=t(g,a[3]);a[4]=t(f,a[4]);a[5]=t(n,a[5]);a[6]=t(k,a[6]);a[7]=t(e,a[7]);return a}var H;H=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206, -2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474, -2756734187,3204031479,3329325298];"function"===typeof define&&define.amd?define(function(){return w}):"undefined"!==typeof exports?("undefined"!==typeof module&&module.exports&&(module.exports=w),exports=w):I.jsSHA=w})(this); - -console.debug("main_background.js"); +console.log("main_background.js");  /**  *	Wrapper around crypto lib  *  */  function hash(source){ -	var shaObj = new jsSHA("SHA-256", "TEXT"); +	var shaObj = new jssha("SHA-256","TEXT")  	shaObj.update(source);  	return shaObj.getHash("HEX");  } @@ -747,8 +719,22 @@ function blocked_status(hash){  	});  }  /* *********************************************************************************************** */ -// (This is part of eval_test.js with a few console.logs/comments removed) - +/** +*	Rigorously determines if code is trivial or not based on the official triviality criterion  +*/ +function full_evaluate(script){ +	try{ +		var ast = window.parse(script); +	}catch(e){ +		console.log("%cError parsing","color:red;"); +		return false; +	} +	console.log(ast); +	return true; +} +/** +*	Performs the initial pass on code to see if it needs to be completely parsed +*/  function evaluate(script,name){  	function reserved_object_regex(object){  		var arith_operators = "\\+\\-\\*\\/\\%\\="; @@ -771,7 +757,7 @@ function evaluate(script,name){  	var reason = ""  	// 	This is where individual "passes" are made over the code  	for(var i = 0; i < reserved_objects.length; i++){ -		var res = reserved_object_regex(reserved_objects[i]).exec(script); +		var res = reserved_object_regex(reserved_objects[i]).exec(temp);  		if(res != null){  			console.log("%c fail","color:red;");  			flag = false;		 @@ -780,7 +766,13 @@ function evaluate(script,name){  	}  	if(flag){  		console.log("%c pass","color:green;"); +	} else{ +		return [flag,reason+"<br>"];  	} +	 +	flag = full_evaluate(temp); + +  	// If flag is set true at this point, the script is trivial  	if(flag){  		reason = "Script was determined to be trivial."; @@ -845,7 +837,6 @@ function license_read(script_src,name){  			return [true,edited_src,reason_text];  		} -onsole.log("Found a license tag");  		var before = unedited_src.substr(0,matches["index"]);  		nontrivial_status = evaluate(before,name);  		if(nontrivial_status[0] == true){ @@ -1003,71 +994,19 @@ function read_script(a){  }  /** -*	Changes the DOM -* -*/ -function DOM_replace(element,newtext){ - - -} -/** -*	Changes the source -* -*/ -function source_replace(html,replace_this,with_this){ -	// This is absolutely neccessary. Not sure if it can cause bugs. -	html = html.replace(/\r\n|\r|\n/g,"\n"); -	replace_this = replace_this.replace(/\r\n|\r|\n/g,"\n"); - -	// Get all match indices -	var match_indices = []; -	 -	var lower_index = 0; - -	while(true){ -		var match_index = html.indexOf(replace_this,lower_index); -		if(match_index == -1){ -			break; -		} else{ -			match_indices.push(lower_index + match_index); -			lower_index += match_index + 1; -		} -	} - -	if(match_indices.length == 0){ -		console.log("%c No matches","color:red;");	 -		// TODO: handle this -	} - -	if(match_indices.length == 1){ -		console.log("%c Matched","color:green;");	 -		html = html.replace(replace_this,with_this);	 -	} - -	if(match_indices.length > 1){ -		console.log("%c Multiple matches","color:orange;");		 -		// TODO: handle this -	} - -	return html; - -} -//source_replace("ababababasdasdasbabababaabababdab","ab","xx"); - -/**  *	Removes noscript tags with name "librejs-path" leaving the inner content to load.  */ -function remove_noscripts(html,doc){ -	for(var i = 0; i < doc.getElementsByName("librejs-path").length; i++){ -		if(doc.getElementsByName("librejs-path")[i].tagName == "NOSCRIPT"){ +function remove_noscripts(html_doc){ +	for(var i = 0; i < html_doc.getElementsByName("librejs-path").length; i++){ +		if(html_doc.getElementsByName("librejs-path")[i].tagName == "NOSCRIPT"){  			debugger;  		}  	} -	return doc.documentElement.innerHTML; +	return html_doc.documentElement.innerHTML;  }  /** -* 	Changes the HTML of a page and the scripts within it. +* 	Reads/changes the HTML of a page and the scripts within it.  *  */  function edit_html(html,url,tabid,wl){ @@ -1084,6 +1023,34 @@ function edit_html(html,url,tabid,wl){  		var amt_scripts = 0;  		var total_scripts = 0;  		var scripts = html_doc.scripts; +	 +		// Deal with intrinsic events + +		var has_intrinsic_events = []; +		for(var i = 0; i < html_doc.all.length; i++){ +			for(var j = 0; j < intrinsic_events.length; j++){ +				if(intrinsic_events[j] in html_doc.all[i].attributes){ +					has_intrinsic_events.push([i,j]); +				} +			} +		} + +		// "i" is an index in html_doc.all +		// "j" is an index in intrinsicEvents +		function edit_event(src,i,j,name){ +			var edited = get_script(src,name); +			edited.then(function(){ +				html_doc.all[i].attributes[intrinsicEvents[j]].value = edited[0]; +			}); +		} + +		// Find all the document's elements with intrinsic events +		for(var i = 0; i < has_intrinsic_events.length; i++){ +			var s_name = "Intrinsic event ["+has_intrinsic_events[i][0]+"]"; +			edit_event(html_doc.all[has_intrinsic_events[i][0]].attributes[intrinsicEvents[has_intrinsic_events[i][1]]].value,has_intrinsic_events[i][0],has_intrinsic_events[i][1],s_name); +		} + +		// Deal with inline scripts  		for(var i = 0; i < scripts.length; i++){  			if(scripts[i].src == ""){ @@ -1093,32 +1060,19 @@ function edit_html(html,url,tabid,wl){  		console.log("Analyzing "+total_scripts+" inline scripts..."); -		var temphtml = html; -  		for(var i = 0; i < scripts.length; i++){  			if(scripts[i].src == ""){  				var edit_script = get_script(scripts[i].innerHTML,url,tabid,wl,i);  				edit_script.then(function(edited){ -					console.log("%c  ------ not remote (document.scripts["+edited[1]+"]) ------","color:white"); -					  					var edited_source = edited[0];  					var unedited_source = html_doc.scripts[edited[1]].innerHTML.trim(); -					/* Source based */ -					//temphtml = source_replace(temphtml,unedited_source,edited_source); -					/* DOM based */  					html_doc.scripts[edited[1]].innerHTML = edited_source;  					amt_scripts++;  					if(amt_scripts >= total_scripts){ -						//console.log(html); -						//console.log(temphtml); -						 -						/* Source based */ -						//resolve(remove_noscripts(temphtml,html_doc)); -						/* DOM based */ -						resolve(remove_noscripts(temphtml,html_doc));					 +						resolve(remove_noscripts(html_doc));					  					}		  				}); @@ -1127,7 +1081,7 @@ function edit_html(html,url,tabid,wl){  		if(total_scripts == 0){  			console.log("Nothing to analyze."); -			resolve(remove_noscripts(temphtml,html_doc)); +			resolve(remove_noscripts(html_doc));  		}  	}); @@ -1142,13 +1096,16 @@ function read_document(a){  		delete unused_data[a["tabId"]];  		console.log("Page Changed!!!");  	} - +	var str = "";  	var filter = webex.webRequest.filterResponseData(a.requestId);  	var decoder = new TextDecoder("utf-8");  	var encoder = new TextEncoder(); // TODO: make sure this doesn't cause undeclared decoding +	filter.onerror = event => { +		console.log("%c Error in getting document","color:red"); +	} +	filter.onstop = event => { +		var test = new ArrayBuffer(); -	filter.ondata = event => { -		var str = decoder.decode(event.data, {stream: true});  		var res = test_url_whitelisted(a.url);  		res.then(function(whitelisted){  			var edit_page; @@ -1167,6 +1124,10 @@ function read_document(a){  			}  		});  	} +	filter.ondata = event => { +		str += decoder.decode(event.data, {stream: true}); +		return;		 +	}  	return {};  } @@ -1182,8 +1143,6 @@ function init_addon(){  	webex.storage.onChanged.addListener(options_listener);  	webex.tabs.onRemoved.addListener(delete_removed_tab_info); -	var targetPage = "https://developer.mozilla.org/en-US/Firefox/Developer_Edition"; -  	// Analyzes remote scripts  	webex.webRequest.onBeforeRequest.addListener(  		read_script, @@ -1291,4 +1250,3 @@ function remove_csv_whitelist(domain){  }  init_addon(); - diff --git a/manifest.json b/manifest.json index ab1c245..9e46fab 100644 --- a/manifest.json +++ b/manifest.json @@ -39,7 +39,7 @@      "html/report_page/report.html"    ],    "background": { -    "scripts": ["main_background.js"] +    "scripts": ["bundle.js"]    }  } diff --git a/test.html b/test.html deleted file mode 100644 index e69de29..0000000 --- a/test.html +++ /dev/null diff --git a/testtag.html b/testtag.html deleted file mode 100644 index 01e98ba..0000000 --- a/testtag.html +++ /dev/null @@ -1,17 +0,0 @@ -<!doctype html> -<html> -	<head> -		<title>A Page containing free JS</title> -	</head> -	<body> -		<div id="bod" style="white-space: pre-wrap;"> -@license magnet:?xt=urn:btih:0ef1b8170b3b615170ff270def6427c317705f85&dn=lgpl-3.0.txt LGPL-3.0 -console.log("free js"); -@license-end -eval("console.log('nontrivial mystery code')"); -@license magnet:?xt=urn:btih:b8999bbaf509c08d127678643c515b9ab0836bae&dn=ISC.txt ISC -console.log("free js"); -@license-end -		</div> -	</body> -</html>  | 
