console.debug("main_background.js"); /** * * Sets global variable "webex" to either "chrome" or "browser" for * use on Chrome or a Firefox variant. * * Change this to support a new browser that isn't Chrome or Firefox, * given that it supports webExtensions. * * (Use the variable "webex" for all API calls after calling this) */ var webex; function set_webex(){ if(typeof(browser) == "undefined"){ webex = chrome; } else{ webex = browser; } } /* * * Called when something changes the persistent data of the add-on. * * The only things that should need to change this data are: * a) The "Whitelist this page" button * b) The options screen * * When the actual blocking is implemented, this will need to comminicate * with its code to update accordingly * */ function options_listener(changes, area){ console.log("Items updated in area" + area +": "); var changedItems = Object.keys(changes); var changed_items = ""; for (var i = 0; i < changedItems.length; i++){ var item = changedItems[i]; changed_items += item + ","; } console.log(changed_items); } /** * Executes the "Display this report in new tab" function * by opening a new tab with whatever HTML is in the popup * at the moment. */ var active_connections = {}; var unused_data = {}; function open_popup_tab(data){ console.log(data); function gotPopup(popupURL){ var creating = webex.tabs.create({"url":popupURL},function(a){ console.log("[TABID:"+a["id"]+"] creating unused data entry from parent window's content"); unused_data[a["id"]] = data; }); } var gettingPopup = webex.browserAction.getPopup({},gotPopup); } /** * * Prints local storage (the persistent data) * */ function debug_delete_local(){ webex.storage.local.clear(); console.log("Local storage cleared"); } /** * * Clears local storage (the persistent data) * */ function debug_print_local(){ function storage_got(items){ console.log("%c Local storage: ", 'color: red;'); for(var i in items){ console.log("%c "+i+" = "+items[i], 'color: blue;'); } } webex.storage.local.get(storage_got); } /** * * This is what you call when a page gets changed to update the info box. * * Sends a message to the content script that updates the popup for a page. * * var example_blocked_info = { * "accepted": [["REASON 1","SOURCE 1"],["REASON 2","SOURCE 2"]], * "blocked": [["REASON 1","SOURCE 1"],["REASON 2","SOURCE 2"]], * "url": "example.com" * } * */ function update_popup(tab_id,blocked_info_arg,update=false){ var new_blocked_data; var blocked_info = blocked_info_arg; if(blocked_info["whitelisted"] === undefined){ blocked_info["whitelisted"] = []; } if(blocked_info["blacklisted"] === undefined){ blocked_info["blacklisted"] = []; } if(blocked_info["accepted"] === undefined){ blocked_info["accepted"] = []; } if(blocked_info["blocked"] === undefined){ blocked_info["blocked"] = []; } function get_sto(items){ //************************************************************************// // Move scripts that are accepted/blocked but whitelisted to "whitelisted" category // (Ideally, they just would not be tested in the first place because that would be faster) var url = blocked_info["url"]; if(url === undefined){ console.error("No url passed to update_popup"); return 1; } function get_status(script_name){ var script_key = encodeURI(url)+" "+encodeURI(script_name); if(items[script_key] === undefined){ return "none"; } return items[script_key]; } function is_bl(script_name){ if(get_status(script_name) == "blacklist"){ return true; } return false; } function is_wl(script_name){ if(get_status(script_name) == "whitelist"){ return true; } return false; } new_blocked_data = { "accepted":[], "blocked":[], "blacklisted":[], "whitelisted":[], "url": url }; for(var type in blocked_info){ for(var script_arr in blocked_info[type]){ if(is_bl(blocked_info[type][script_arr][0])){ new_blocked_data["blacklisted"].push(blocked_info[type][script_arr]); //console.log("Script " + blocked_info[type][script_arr][0] + " is blacklisted"); continue; } if(is_wl(blocked_info[type][script_arr][0])){ new_blocked_data["whitelisted"].push(blocked_info[type][script_arr]); //console.log("Script " + blocked_info[type][script_arr][0] + " is whitelisted"); continue; } if(type == "url"){ continue; } // either "blocked" or "accepted" new_blocked_data[type].push(blocked_info[type][script_arr]); //console.log("Script " + blocked_info[type][script_arr][0] + " isn't whitelisted or blacklisted"); } } //***********************************************************************************************// // store the blocked info until it is opened and needed if(update == false && active_connections[tab_id] === undefined){ console.log("[TABID:"+tab_id+"]"+"Storing blocked_info for when the browser action is opened or asks for it."); unused_data[tab_id] = new_blocked_data; } else{ unused_data[tab_id] = new_blocked_data; console.log("[TABID:"+tab_id+"]"+"Sending blocked_info directly to browser action"); active_connections[tab_id].postMessage({"show_info":new_blocked_data}); delete active_connections[tab_id]; } } webex.storage.local.get(get_sto); } /** * * This is the callback where the content scripts of the browser action will contact the background script. * */ var portFromCS; function connected(p) { p.onMessage.addListener(function(m) { /** * Updates the entry of the current URL in storage */ function set_script(script,val){ if(val != "whitelist" && val != "forget" && val != "blacklist"){ console.error("Key must be either 'whitelist', 'blacklist' or 'forget'"); } // (Remember that we do not trust the names of scripts.) var current_url = ""; function geturl(tabs) { current_url = tabs[0]["url"]; // The space char is a valid delimiter because encodeURI() replaces it with %20 var scriptkey = encodeURI(current_url)+" "+encodeURI(script); if(val == "forget"){ var prom = webex.storage.local.remove(scriptkey); // TODO: This should produce a "Refresh the page for this change to take effect" message } else{ var newitem = {}; newitem[scriptkey] = val; webex.storage.local.set(newitem); } } var querying = webex.tabs.query({active: true,currentWindow: true},geturl); return; } var update = false; var contact_finder = false; if(m["whitelist"] !== undefined){ set_script(m["whitelist"][0],"whitelist"); update = true; } if(m["blacklist"] !== undefined){ set_script(m["blacklist"][0],"blacklist"); update = true; } if(m["forget"] !== undefined){ set_script(m["forget"][0],"forget"); update = true; } // if(m["open_popup_tab"] !== undefined){ open_popup_tab(m["open_popup_tab"]); } // a debug feature if(m["printlocalstorage"] !== undefined){ debug_print_local(); } // invoke_contact_finder if(m["invoke_contact_finder"] !== undefined){ contact_finder = true; inject_contact_finder(); } // a debug feature (maybe give the user an option to do this?) if(m["deletelocalstorage"] !== undefined){ debug_delete_local(); } function logTabs(tabs) { if(contact_finder){ console.log("[TABID:"+tab_id+"] Injecting contact finder"); inject_contact_finder(tabs[0]["id"]); } if(update){ // TODO: check the Firefox equivalent reserved URL pattern if(typeof(tabs[0]["url"].match(/chrome\-extension:\/\/.*display-panel\.html/g)) == "object"){ console.log("%c Not updating popup because this is a reserved page","color: red;"); return; } else{ console.log("%c updating tab "+tabs[0]["id"],"color: red;"); update_popup(tabs[0]["id"],unused_data[tabs[0]["id"]],true); active_connections[tabs[0]["id"]] = p; } } for(var i = 0; i < tabs.length; i++) { var tab = tabs[i]; var tab_id = tab["id"]; if(unused_data[tab_id] !== undefined){ // If we have some data stored here for this tabID, send it console.log("[TABID:"+tab_id+"]"+"Sending stored data associated with browser action"); p.postMessage({"show_info":unused_data[tab_id]}); } else{ // create a new entry unused_data[tab_id] = {"url":tab["url"],"blocked":"","accepted":""}; p.postMessage({"show_info":unused_data[tab_id]}); console.log("[TABID:"+tab_id+"]"+"No data found, creating a new entry for this window."); } } } var querying = webex.tabs.query({active: true,currentWindow: true},logTabs); }); } /** * The callback for tab closings. * * Delete the info we are storing about this tab if there is any. * */ function delete_removed_tab_info(tab_id, remove_info){ console.log("[TABID:"+tab_id+"]"+"Deleting stored info about closed tab"); if(unused_data[tab_id] !== undefined){ delete unused_data[tab_id]; } if(active_connections[tab_id] !== undefined){ delete active_connections[tab_id]; } } /** * Initializes various add-on functions * only meant to be called once when the script starts */ function init_addon(){ set_webex(); webex.runtime.onConnect.addListener(connected); webex.storage.onChanged.addListener(options_listener); webex.tabs.onRemoved.addListener(delete_removed_tab_info); /**************** some debugging: ***************************/ // Valid input for update_popup var example_input = { "accepted": [["FILENAME 1","REASON 1"],["FILENAME 2","REASON 2"]], "blocked": [["FILENAME 3","REASON 1"],["FILENAME 4","REASON 2"]], "url":"chrome://extensions/" }; // To test the default text update_popup(4,example_input); console.log("Set the browser action contents"); /*****************************************************************/ } /** * Test if a page is whitelisted/blacklisted. * * The input here is tested against the comma seperated string found in the options. * * It does NOT test against the individual entries created by hitting the "whitelist" * button for a script in the browser action. * * * */ function test_url_whitelisted(url,callback){ function storage_got(items){ var wl = items["pref_whitelist"].split(","); var regex; for(i in wl){ var s = wl[i].replace(/\*/g,"\\S*"); s = s.replace(/\./g,"\\."); regex = new RegExp(s, "g"); if(url.match(regex)){ //callback("%c" + wl[i] + " matched " + url,"color: purple;"); callback(true); } else{ //console.log("%c" + wl[i] + " didn't match " + url,"color: #dd0000;"); } } callback(false); } webex.storage.local.get(storage_got); } function inject_contact_finder(tab_id){ function executed(result) { console.log("[TABID:"+tab_id+"]"+"finished executing contact finder: " + result); } var executing = webex.tabs.executeScript(tab_id, {file: "/contact_finder.js"}, executed); } init_addon(); /***************** test the comma seperated whitelist *****************/ /* var test_urls = [ "example.subdomain.test.com/", "http://example.subdomain.test.com", "http://0xbeef.coffee", "https://webchat.freenode.net/", "https://www.chromium.org/Home/chromium-security/client-identification-mechanisms", "http://stackoverflow.com/questions/874709", "https://postcalc.usps.com", "http://regexr.com/", "https://pgw.ceca.es/tpvweb/tpv/compra.action", "This is total garbage input", "http://home.com/test", "https://home.com/test" ] function callback(a){console.log(a);} for(i in test_urls){ test_url_whitelisted(test_urls[i],callback); } */ /*******************************************************************/