From 8db73a1cc5de75bbf4ef96d4e4141de39110aea1 Mon Sep 17 00:00:00 2001 From: gorhill Date: Mon, 10 Feb 2014 15:08:58 -0500 Subject: [PATCH] changes for v0.8.0.0 --- assets/httpsb/preset-recipes-1st.yaml | 362 +++++++++++++++++--------- assets/httpsb/preset-recipes-3rd.yaml | 24 +- css/rulemanager.css | 10 +- js/async.js | 9 +- js/contentscripthandlers.js | 13 +- js/contextmenu.js | 2 +- js/cookies.js | 4 +- js/httpsb.js | 94 ++++++- js/info.js | 2 +- js/popup.js | 15 +- js/presets.js | 223 +++++++++++----- js/rulemanager.js | 84 +++--- js/start.js | 36 +-- js/tab.js | 160 +++++------- js/traffic.js | 28 +- rulemanager.html | 3 +- 16 files changed, 689 insertions(+), 380 deletions(-) diff --git a/assets/httpsb/preset-recipes-1st.yaml b/assets/httpsb/preset-recipes-1st.yaml index d5d7ea1..51b611b 100644 --- a/assets/httpsb/preset-recipes-1st.yaml +++ b/assets/httpsb/preset-recipes-1st.yaml @@ -42,28 +42,38 @@ Ars Technica: keys: arstechnica.com - whitelist: | - * arstechnica.com - * arstechnica.net + scope: arstechnica.com + whitelist: | + * arstechnica.com + * arstechnica.net Businessweek: keys: www.businessweek.com - whitelist: | - * businessweek.com - * btrd.net + scope: www.businessweek.com + whitelist: | + * businessweek.com + * btrd.net CNN: - keys: cnn.com - whitelist: | - * cnn.com - * turner.com + keys: '*.cnn.com' + scope: '*.cnn.com' + whitelist: | + * cnn.com + frame cnn.com + * turner.com + * cnn-f.akamaihd.net + +Daily Motion: + keys: www.dailymotion.com + scope: www.dailymotion.com + whitelist: | + * dailymotion.com + * dmcdn.net Fox News: - keys: www.foxnews.com + keys: '*.foxnews.com' scope: '*.foxnews.com' whitelist: | - css * - image * * foxnews.com * fncstatic.com # Necessary for legitimate images to show @@ -76,11 +86,9 @@ Fox News: Facebook: facode: f09a - keys: www.facebook.com + keys: '*.facebook.com' scope: '*.facebook.com' whitelist: | - css * - image * * facebook.com * fbcdn.net * fbstatic-a.akamaihd.net @@ -89,150 +97,262 @@ Facebook: Github: facode: f09b keys: github.com - whitelist: | - * github.com - * githubapp.com - * github.global.ssl.fastly.net - * github-camo.global.ssl.fastly.net + scope: 'github.com' + whitelist: | + * github.com + * githubapp.com + * github.global.ssl.fastly.net + * github-camo.global.ssl.fastly.net Google Account: keys: accounts.google.com + requires: Google Plus scope: accounts.google.com - whitelist: | - * google.com - * googleusercontent.com - * ssl.gstatic.com - * accounts.youtube.com - frame accounts.youtube.com + whitelist: | + * google.com + * googleusercontent.com + * ssl.gstatic.com + frame accounts.youtube.com + scope: accounts.youtube.com + whitelist: | + * accounts.youtube.com + frame accounts.youtube.com + +Google Plus: + keys: plus.google.com + requires: Google Account + scope: plus.google.com + whitelist: | + * google.com + frame google.com + * gstatic.com + * googleusercontent.com + +Google Search: + keys: www.google.com + scope: www.google.com + whitelist: | + * google.com + frame accounts.youtube.com + +Google Search Canada: + keys: www.google.ca + scope: www.google.ca + whitelist: | + * www.google.ca + +Google Groups Discussions: + keys: | + groups.google.com + scope: groups.google.com + whitelist: | + * groups.google.com + * www.google.com + * gstatic.com + +Google Groups Discussions (with account): + keys: groups.google.com + requires: | + Google Account + Google Groups Discussions + +Google Product Forums: + keys: productforums.google.com + scope: productforums.google.com + whitelist: | + * productforums.google.com + * www.google.com + * gstatic.com + +Google Product Forums (with account): + keys: productforums.google.com + requires: | + Google Account + Google Product Forums Google News: keys: news.google.com - whitelist: | - * news.google.com - * gstatic.com + scope: news.google.com + whitelist: | + * news.google.com + * gstatic.com + +Google News (with account): + keys: news.google.com + requires: | + Google Account + Google News The Guardian: keys: www.theguardian.com - whitelist: | - * theguardian.com - frame discussion.theguardian.com - * guim.co.uk - * guardianapis.com - * guardianapps.co.uk - * guardian.co.uk - * theguardian.tv + scope: www.theguardian.com + whitelist: | + * theguardian.com + frame discussion.theguardian.com + * guim.co.uk + * guardianapis.com + * guardianapps.co.uk + * guardian.co.uk + * theguardian.tv Huffington Post: keys: www.huffingtonpost.com - whitelist: | - * huffingtonpost.com - * huffpost.com + scope: www.huffingtonpost.com + whitelist: | + * huffingtonpost.com + * huffpost.com + +JSFIDDLE: + keys: jsfiddle.net + scope: jsfiddle.net + whitelist: | + * jsfiddle.net + * jshell.net + frame jshell.net + * togetherjs.com Mashable: keys: mashable.com - whitelist: | - * mashable.com - * mshcdn.com + scope: mashable.com + whitelist: | + * mashable.com + * mshcdn.com NBC News: - keys: nbcnews.com - whitelist: | - * nbcnews.com + keys: www.nbcnews.com + scope: www.nbcnews.com + whitelist: | + * nbcnews.com New York Times: keys: nytimes.com - whitelist: | - * nytimes.com - * nyt.com + scope: www.nytimes.com + whitelist: | + * nytimes.com + * nyt.com -Wikipedia: - keys: wikipedia.org - whitelist: | - * wikipedia.org - * wikimedia.org - -Reddit: - keys: reddit.com - whitelist: | - * reddit.com - * redditmedia.com - * redditstatic.com - * redditstatic.s3.amazonaws.com - -Twitter: +New York Times (with account): + keys: myaccount.nytimes.com + requires: New York Times + scope: myaccount.nytimes.com + whitelist: | + * nytimes.com + +Reddit (with account): + keys: | + reddit.com + ssl.reddit.com + scope: www.reddit.com + whitelist: | + * reddit.com + * redditmedia.com + * redditstatic.com + * redditstatic.s3.amazonaws.com + scope: ssl.reddit.com + whitelist: | + * reddit.com + * redditstatic.s3.amazonaws.com + +Twitter (with account): keys: twitter.com - whitelist: | - * twitter.com - * twimg.com + scope: twitter.com + whitelist: | + * twitter.com + * twimg.com The Verge: keys: www.theverge.com - whitelist: | - * theverge.com - * sbnation.com + scope: www.theverge.com + whitelist: | + * theverge.com + * sbnation.com The Wall Street Journal: - keys: wsj.com - whitelist: | - * wsj.com - frame wsj.com - * wsj.net - -Washington Post: - keys: washingtonpost.com - whitelist: | - * washingtonpost.com - * troveread.com - * wpdigital.net + keys: | + online.wsj.com + stream.wsj.com + scope: '*.wsj.com' + whitelist: | + * wsj.com + frame wsj.com + * wsj.net + * a248.e.akamai.net + +Washington Post (with account): + keys: www.washingtonpost.com + scope: www.washingtonpost.com + whitelist: | + * washingtonpost.com + * troveread.com + * wpdigital.net + scope: account.washingtonpost.com + whitelist: | + * washingtonpost.com + * wpidentity.s3.amazonaws.com + +Wikipedia: + keys: '*.wikipedia.org' + scope: '*.wikipedia.org' + whitelist: | + * wikipedia.org + * wikimedia.org Wired: - keys: wired.com - whitelist: | - * wired.com - frame wired.com - * fonts.condenast.com - # For WIRED VIDEO - * cnevids.com - frame player.cnevids.com - * dnkzzz1hlto79.cloudfront.net - * dp8hsntg6do36.cloudfront.net + keys: '*.wired.com' + scope: '*.wired.com' + whitelist: | + * wired.com + frame wired.com + * fonts.condenast.com + # For WIRED VIDEO + * cnevids.com + frame player.cnevids.com + * dnkzzz1hlto79.cloudfront.net + * dp8hsntg6do36.cloudfront.net + * dwgyu36up6iuz.cloudfront.net Wired UK: keys: www.wired.co.uk - whitelist: | - * wired.co.uk - # for 'css' - * d3u12z27ui3vom.cloudfront.net - # needed for the nav menu - script ajax.googleapis.com + scope: www.wired.co.uk + whitelist: | + * wired.co.uk + # for 'css' + * d3u12z27ui3vom.cloudfront.net + # needed for the nav menu + script ajax.googleapis.com Yahoo News: keys: news.yahoo.com - whitelist: | - * news.yahoo.com - * yimg.com - -# TODO: multiple scopes, logging in does not work properly + scope: news.yahoo.com + whitelist: | + * news.yahoo.com + * yimg.com Youtube: facode: f167 keys: www.youtube.com scope: www.youtube.com - whitelist: | - css * - image * - * youtube.com - frame youtube.com - * youtube-nocookie.com - * ytimg.com - * googlevideo.com - * ggpht.com - # As per issue #169 - * youtube.googleapis.com - * plus.googleapis.com - frame plus.googleapis.com - cookie accounts.google.com - script accounts.google.com - frame google.com - * apis.google.com + whitelist: | + * youtube.com + frame youtube.com + * youtube-nocookie.com + * ytimg.com + * googlevideo.com + * google.com + * ggpht.com + # As per issue #169 + * youtube.googleapis.com + * plus.googleapis.com + frame plus.googleapis.com + cookie accounts.google.com + script accounts.google.com + frame google.com + * apis.google.com + +Youtube (with account): + facode: f167 + keys: www.youtube.com + requires: | + Youtube + Google Account diff --git a/assets/httpsb/preset-recipes-3rd.yaml b/assets/httpsb/preset-recipes-3rd.yaml index b33b22b..49e97f2 100644 --- a/assets/httpsb/preset-recipes-3rd.yaml +++ b/assets/httpsb/preset-recipes-3rd.yaml @@ -46,6 +46,17 @@ Brightcove: plugin brightcove.com script brightcove.com +Daily Motion: + facode: f008 + keys: www.dailymotion.com + whitelist: | + plugin www.dailymotion.com + script www.dailymotion.com + frame www.dailymotion.com + plugin dmcdn.net + script dmcdn.net + script ajax.googleapis.com + Disqus: facode: f086 keys: disqus.com @@ -60,7 +71,9 @@ Disqus: Facebook: facode: f09a - keys: facebook.com + keys: | + facebook.com + connect.facebook.net whitelist: | script facebook.com xhr facebook.com @@ -95,6 +108,15 @@ Livefyre: script fyre.co xhr fyre.co +Ooyala player: + facode: f008 + keys: player.ooyala.com + whitelist: | + plugin player.ooyala.com + script player.ooyala.com + xhr player.ooyala.com + plugin opf.ooyala.com + Pinterest: facode: f0d2 keys: pinterest.com diff --git a/css/rulemanager.css b/css/rulemanager.css index 5f11d7c..279f353 100644 --- a/css/rulemanager.css +++ b/css/rulemanager.css @@ -9,15 +9,15 @@ h1:first-child { } #navi-bar { border-bottom: 1px solid #ccc; - padding: 1em; + padding: 0.5em; position: fixed; background-color: white; width: 100%; - height: 8em; + height: 7em; z-index: 100; } #navi-bar + div { - padding: 10em 1em 1em 1em; + padding: 8em 0.5em 1em 0.5em; } h2 { margin: 0.5em 0; @@ -48,7 +48,7 @@ button { margin: 0.5em 1em 0 0; border: 1px solid rgba(0,0,0,0.2); border-radius: 5px; - padding: 0.5em 1em; + padding: 0.25em 0.75em; font: inherit; font-size: 110%; background-color: #eee; @@ -56,7 +56,7 @@ button { } button .fa { margin-right: 0.5em; - font-size: larger; + font-size: large; } #recipeDecode, #recipeImport, #recipeEncode, #recipeExport { diff --git a/js/async.js b/js/async.js index e7d2379..1f6e3e1 100644 --- a/js/async.js +++ b/js/async.js @@ -96,14 +96,15 @@ setInterval(asyncJobQueueHandler, asyncJobQueue.resolution); // A time out is used to coalesce adjacents requests to update badge. function updateBadgeCallback(pageUrl) { - if ( pageUrl === HTTPSB.behindTheSceneURL ) { + var httpsb = HTTPSB; + if ( pageUrl === httpsb.behindTheSceneURL ) { return; } - var tabId = tabIdFromPageUrl(pageUrl); + var tabId = httpsb.tabIdFromPageUrl(pageUrl); if ( !tabId ) { return; } - var pageStats = pageStatsFromTabId(tabId); + var pageStats = httpsb.pageStatsFromTabId(tabId); if ( pageStats ) { pageStats.updateBadge(tabId); } else { @@ -228,7 +229,7 @@ function onMessageHandler(request, sender, callback) { break; case 'forceReloadTab': - forceReload(request.pageURL); + HTTPSB.forceReload(request.pageURL); break; case 'checkScriptBlacklisted': diff --git a/js/contentscripthandlers.js b/js/contentscripthandlers.js index 94b9027..44b2037 100644 --- a/js/contentscripthandlers.js +++ b/js/contentscripthandlers.js @@ -30,7 +30,7 @@ function contentScriptSummaryHandler(details, sender) { } var ut = uriTools; var httpsb = HTTPSB; - var pageURL = pageUrlFromTabId(sender.tab.id); + var pageURL = httpsb.pageUrlFromTabId(sender.tab.id); var frameURL = ut.normalizeURI(details.locationURL); var pageHostname = ut.hostname(); var urls, url, hostname, block; @@ -58,7 +58,7 @@ function contentScriptSummaryHandler(details, sender) { hostname = pageHostname; } block = httpsb.blacklisted(pageURL, 'script', hostname); - recordFromPageUrl(pageURL, 'script', url, block); + httpsb.recordFromPageUrl(pageURL, 'script', url, block); } // plugins @@ -74,7 +74,7 @@ function contentScriptSummaryHandler(details, sender) { hostname = pageHostname; } block = httpsb.blacklisted(pageURL, 'object', hostname); - recordFromPageUrl(pageURL, 'object', url, block); + httpsb.recordFromPageUrl(pageURL, 'object', url, block); } } @@ -83,7 +83,12 @@ function contentScriptSummaryHandler(details, sender) { function contentScriptLocalStorageHandler(pageURL) { var httpsb = HTTPSB; var response = httpsb.blacklisted(pageURL, 'cookie', uriTools.hostnameFromURI(pageURL)); - recordFromPageUrl(pageURL, 'cookie', uriTools.rootURLFromURI(pageURL) + '/{localStorage}', response); + httpsb.recordFromPageUrl( + pageURL, + 'cookie', + uriTools.rootURLFromURI(pageURL) + '/{localStorage}', + response + ); response = response && httpsb.userSettings.deleteLocalStorage; if ( response ) { httpsb.localStorageRemovedCounter++; diff --git a/js/contextmenu.js b/js/contextmenu.js index 16867b3..0f6188b 100644 --- a/js/contextmenu.js +++ b/js/contextmenu.js @@ -84,7 +84,7 @@ function contextMenuClickHandler(info, tab) { switch ( info.menuItemId ) { case 'gdt-group0': HTTPSB.whitelistTemporarily(pageURL, '*', pageDomain); - smartReloadTab(tab.id); + HTTPSB.smartReloadTab(tab.id); break; case 'revertScopeRules': diff --git a/js/cookies.js b/js/cookies.js index 93c5a0d..fd31d4d 100644 --- a/js/cookies.js +++ b/js/cookies.js @@ -136,7 +136,7 @@ var cookieHunter = { if ( !pageStats ) { return; } - var pageURL = pageUrlFromPageStats(pageStats); + var pageURL = HTTPSB.pageUrlFromPageStats(pageStats); this.queuePageRecord[pageURL] = pageStats; asyncJobQueue.add( 'cookieHunterPageRecord', @@ -182,7 +182,7 @@ var cookieHunter = { if ( !pageStats ) { return; } - var pageURL = pageUrlFromPageStats(pageStats); + var pageURL = HTTPSB.pageUrlFromPageStats(pageStats); this.queuePageRemove[pageURL] = pageStats; asyncJobQueue.add( 'cookieHunterPageRemove', diff --git a/js/httpsb.js b/js/httpsb.js index c36eede..34f84cf 100644 --- a/js/httpsb.js +++ b/js/httpsb.js @@ -46,8 +46,11 @@ HTTPSB.domainScopeKeyFromURL = function(url) { if ( scheme.indexOf('http') !== 0 ) { return ''; } - var hostname = ut.hostname(); - var domain = ut.domainFromHostname(hostname); + return this.domainScopeKeyFromHostname(ut.hostname()); +}; + +HTTPSB.domainScopeKeyFromHostname = function(hostname) { + var domain = uriTools.domainFromHostname(hostname); if ( domain === '' ) { domain = hostname; } @@ -58,6 +61,10 @@ HTTPSB.siteScopeKeyFromURL = function(url) { return uriTools.hostnameFromURI(url); }; +HTTPSB.siteScopeKeyFromHostname = function(hostname) { + return hostname; +}; + /******************************************************************************/ HTTPSB.isGlobalScopeKey = function(scopeKey) { @@ -98,6 +105,12 @@ HTTPSB.permanentScopeFromScopeKey = function(scopeKey) { /******************************************************************************/ +HTTPSB.temporaryScopeExists = function(scopeKey) { + return !!this.temporaryScopeFromScopeKey(scopeKey); +}; + +/******************************************************************************/ + // Of course this doesn't make sense as there is always a global scope, but // what makes sense is that we need to remove site and domain scopes for // global scope to take effect. @@ -136,7 +149,7 @@ HTTPSB.createTemporaryDomainScope = function(url) { scope = new PermissionScope(); scope.whitelist('main_frame', '*'); this.temporaryScopes.scopes[scopeKey] = scope; - this.copyRulesTemporarily(scopeKey, this.globalScopeKey(), url); + this.copyTemporaryRules(scopeKey, this.globalScopeKey(), url); } else if ( scope.off ) { scope.off = false; } @@ -179,8 +192,8 @@ HTTPSB.createTemporarySiteScope = function(url) { scope = new PermissionScope(); scope.whitelist('main_frame', '*'); this.temporaryScopes.scopes[scopeKey] = scope; - this.copyRulesTemporarily(scopeKey, this.globalScopeKey(), url); - this.copyRulesTemporarily(scopeKey, this.domainScopeKeyFromURL(url), url); + this.copyTemporaryRules(scopeKey, this.globalScopeKey(), url); + this.copyTemporaryRules(scopeKey, this.domainScopeKeyFromURL(url), url); } else { scope.off = false; } @@ -247,6 +260,36 @@ HTTPSB.removePermanentScopeFromScopeKey = function(scopeKey, persist) { /******************************************************************************/ +HTTPSB.revealTemporaryDomainScope = function(domainScopeKey) { + if ( !this.isDomainScopeKey(domainScopeKey) ) { + return; + } + // Remove '*' prefix + var keySuffix = domainScopeKey.slice(1); + var keySuffixLen = keySuffix.length; + var scopes = this.temporaryScopes.scopes; + var pos; + for ( var scopeKey in scopes ) { + if ( !scopes.hasOwnProperty(scopeKey) ) { + continue; + } + if ( scopeKey === domainScopeKey ) { + continue; + } + pos = scopeKey.lastIndexOf(keySuffix); + if ( pos < 0 ) { + continue; + } + if ( pos !== scopeKey.length - keySuffixLen ) { + continue; + } + // Turn off scope + scopes[scopeKey].off = true; + } +}; + +/******************************************************************************/ + HTTPSB.temporaryScopeKeyFromPageURL = function(url) { return this.temporaryScopes.scopeKeyFromPageURL(url); }; @@ -342,14 +385,20 @@ HTTPSB.autoCreateTemporarySiteScope = function(pageURL) { // Copy rules from another scope. If a pageURL is provided, // it will be used to filter the rules according to the hostname. -HTTPSB.copyRulesTemporarily = function(toScopeKey, fromScopeKey, pageURL) { - var toScope = this.temporaryScopes.scopes[toScopeKey]; - var fromScope = this.temporaryScopes.scopes[fromScopeKey]; +HTTPSB.copyTemporaryRules = function(toScopeKey, fromScopeKey, pageURL) { + this.copyTemporaryWhiteRules(toScopeKey, fromScopeKey, pageURL); + this.copyTemporaryGrayRules(toScopeKey, fromScopeKey); + this.copyTemporaryBlackRules(toScopeKey, fromScopeKey); +}; + +HTTPSB.copyTemporaryWhiteRules = function(toScopeKey, fromScopeKey, pageURL) { + var toScope = this.temporaryScopeFromScopeKey(toScopeKey); + var fromScope = this.temporaryScopeFromScopeKey(fromScopeKey); if ( !toScope || !fromScope ) { return; } var ut = uriTools; - var pageStats = pageStatsFromPageUrl(pageURL); + var pageStats = this.pageStatsFromPageUrl(pageURL); var hostnames = pageStats ? pageStats.domains : {}; var domains = {}; for ( var hostname in hostnames ) { @@ -371,10 +420,26 @@ HTTPSB.copyRulesTemporarily = function(toScopeKey, fromScopeKey, pageURL) { } toScope.white.addOne(ruleKey); } - toScope.black.fromList(fromScope.black); +}; + +HTTPSB.copyTemporaryGrayRules = function(toScopeKey, fromScopeKey) { + var toScope = this.temporaryScopeFromScopeKey(toScopeKey); + var fromScope = this.temporaryScopeFromScopeKey(fromScopeKey); + if ( !toScope || !fromScope ) { + return; + } toScope.gray.fromList(fromScope.gray); }; +HTTPSB.copyTemporaryBlackRules = function(toScopeKey, fromScopeKey) { + var toScope = this.temporaryScopeFromScopeKey(toScopeKey); + var fromScope = this.temporaryScopeFromScopeKey(fromScopeKey); + if ( !toScope || !fromScope ) { + return; + } + toScope.black.fromList(fromScope.black); +}; + /******************************************************************************/ // Whitelist something @@ -556,9 +621,6 @@ HTTPSB.savePermissions = function() { if ( chrome.runtime.lastError ) { console.error('HTTP Switchboard > saved permissions: %s', chrome.runtime.lastError.message()); } - chrome.storage.local.getBytesInUse('scopes', function(bytesInUse) { - // console.log('HTTP Switchboard > saved permissions: %d bytes used', bytesInUse); - }); // Remove pre-v0.5.0 obsolete entries // TODO: Can be removed once everybody is using v0.5.0 or above chrome.storage.local.remove(['whitelist','blacklist','graylist']); @@ -593,3 +655,9 @@ HTTPSB.turnOn = function() { this.off = false; }; + +/******************************************************************************/ + +HTTPSB.isOpera = function() { + return navigator.userAgent.indexOf(' OPR/') > 0; +}; diff --git a/js/info.js b/js/info.js index a4205a5..a5331ac 100644 --- a/js/info.js +++ b/js/info.js @@ -35,7 +35,7 @@ function gethttpsb() { } function pageStatsFromPageUrl(pageUrl) { - return chrome.extension.getBackgroundPage().HTTPSB.pageStats[pageUrl]; + return gethttpsb().pageStatsFromPageUrl(pageUrl); } /******************************************************************************/ diff --git a/js/popup.js b/js/popup.js index fdc54dd..4229b64 100644 --- a/js/popup.js +++ b/js/popup.js @@ -43,7 +43,7 @@ function getHTTPSB() { } function getPageStats() { - return getBackgroundPage().pageStatsFromTabId(HTTPSBPopup.tabId); + return getHTTPSB().pageStatsFromTabId(HTTPSBPopup.tabId); } /******************************************************************************/ @@ -1274,13 +1274,10 @@ function populatePresets() { function presetEntryHandler() { var httpsb = getHTTPSB(); - var presetId = $(this).prop('presetId'); - var preset = httpsb.presetManager.presetFromId(presetId); - if ( !preset ) { - return; - } - var scopeKey = httpsb.temporaryScopeKeyFromPageURL(HTTPSBPopup.pageURL); - preset.applyToScope(scopeKey); + httpsb.presetManager.applyToScope( + httpsb.temporaryScopeKeyFromPageURL(HTTPSBPopup.pageURL), + $(this).prop('presetId') + ); updateScopeCell(); updateMatrixStats(); updateMatrixColors(); @@ -1339,7 +1336,7 @@ function bindToTabHandler(tabs) { HTTPSBPopup.tabId = httpsb.behindTheSceneTabId; } else { HTTPSBPopup.tabId = tab.id; - HTTPSBPopup.pageURL = background.pageUrlFromTabId(HTTPSBPopup.tabId); + HTTPSBPopup.pageURL = httpsb.pageUrlFromTabId(HTTPSBPopup.tabId); } HTTPSBPopup.pageHostname = background.uriTools.hostnameFromURI(HTTPSBPopup.pageURL); HTTPSBPopup.pageDomain = background.uriTools.domainFromHostname(HTTPSBPopup.pageHostname); diff --git a/js/presets.js b/js/presets.js index f9e75d4..41a9732 100644 --- a/js/presets.js +++ b/js/presets.js @@ -22,93 +22,69 @@ /******************************************************************************/ HTTPSB.PresetRecipe = function() { + this.firstParty = undefined; this.id = undefined; this.name = ''; this.facode = 0; this.keys = {}; + this.requires = null; this.whitelist = {}; this.scopes = {}; -}; - -/******************************************************************************/ - -HTTPSB.PresetRecipe.prototype.applyToScope = function(scopeKey) { - var httpsb = HTTPSB; - var rules, ruleKey, pos; - - // Unscoped rules - rules = this.whitelist; - for ( ruleKey in rules ) { - if ( !rules.hasOwnProperty(ruleKey) ) { - continue; - } - pos = ruleKey.indexOf('|'); - httpsb.whitelistTemporarily(scopeKey, ruleKey.slice(0, pos), ruleKey.slice(pos + 1)); - } - - // Scoped rules - var scopes = this.scopes; - for ( scopeKey in scopes ) { - if ( !scopes.hasOwnProperty(scopeKey) ) { - continue; - } - httpsb.createTemporaryScopeFromScopeKey(scopeKey); - rules = scopes[scopeKey].whitelist; - for ( ruleKey in rules ) { - if ( !rules.hasOwnProperty(ruleKey) ) { - continue; - } - pos = ruleKey.indexOf('|'); - httpsb.whitelistTemporarily(scopeKey, ruleKey.slice(0, pos), ruleKey.slice(pos + 1)); - } - } + this.barrier = 0; }; /******************************************************************************/ HTTPSB.PresetManager = function() { this.presets = {}; - this.firstPartyDict = {}; - this.thirdPartyDict = {}; + this.hostnameTo1stPartyPresetMap = {}; + this.hostnameTo3rdPartyPresetMap = {}; + this.firstPartyNameToPresetMap = {}; this.idGenerator = 1; }; /******************************************************************************/ HTTPSB.PresetManager.prototype.rememberFirstParty = function(preset) { + preset.firstParty = true; preset.id = this.idGenerator++; this.presets[preset.id] = preset; + this.firstPartyNameToPresetMap[preset.name] = preset; + var hostnameTo1stPartyPresetMap = this.hostnameTo1stPartyPresetMap; var ut = uriTools; - var pageHostnames = Object.keys(preset.keys); - var i = pageHostnames.length; - var pageHostname, hostnames, j, hostname; + var hostnames = Object.keys(preset.keys); + var i = hostnames.length; + var hostname; while ( i-- ) { - pageHostname = pageHostnames[i]; - hostnames = ut.allHostnamesFromHostname(pageHostname); - j = hostnames.length; - while ( j-- ) { - hostname = hostnames[j]; - if ( !this.firstPartyDict[hostname] ) { - this.firstPartyDict[hostname] = [preset]; - } else { - this.firstPartyDict[hostname].push(preset); + hostname = hostnames[i]; + if ( !hostnameTo1stPartyPresetMap[hostname] ) { + hostnameTo1stPartyPresetMap[hostname] = preset; + } else { + if ( hostnameTo1stPartyPresetMap[hostname] instanceof HTTPSB.PresetRecipe ) { + hostnameTo1stPartyPresetMap[hostname] = [hostnameTo1stPartyPresetMap[hostname]]; } + hostnameTo1stPartyPresetMap[hostname].push(preset); } } }; HTTPSB.PresetManager.prototype.rememberThirdParty = function(preset) { + preset.firstParty = false; preset.id = this.idGenerator++; this.presets[preset.id] = preset; + var hostnameTo3rdPartyPresetMap = this.hostnameTo3rdPartyPresetMap; var hostnames = Object.keys(preset.keys); var i = hostnames.length; var hostname; while ( i-- ) { hostname = hostnames[i]; - if ( !this.thirdPartyDict[hostname] ) { - this.thirdPartyDict[hostname] = [preset]; + if ( !hostnameTo3rdPartyPresetMap[hostname] ) { + hostnameTo3rdPartyPresetMap[hostname] = preset; } else { - this.thirdPartyDict[hostname].push(preset); + if ( hostnameTo3rdPartyPresetMap[hostname] instanceof HTTPSB.PresetRecipe ) { + hostnameTo3rdPartyPresetMap[hostname] = [hostnameTo3rdPartyPresetMap[hostname]]; + } + this.hostnameTo3rdPartyPresetMap[hostname].push(preset); } } }; @@ -122,7 +98,7 @@ HTTPSB.PresetManager.prototype.presetFromId = function(presetId) { /******************************************************************************/ HTTPSB.PresetManager.prototype.firstPartyFromHostname = function(hostname) { - var presets = this.firstPartyDict[hostname]; + var presets = this.hostnameTo1stPartyPresetMap[hostname]; if ( presets ) { return presets[0]; } @@ -131,20 +107,26 @@ HTTPSB.PresetManager.prototype.firstPartyFromHostname = function(hostname) { /******************************************************************************/ +HTTPSB.PresetManager.prototype.firstPartyFromName = function(name) { + return this.firstPartyNameToPresetMap[name]; +}; + +/******************************************************************************/ + HTTPSB.PresetManager.prototype.findMatches = function(firstParty, thirdParties) { var presets, preset; var matches = []; var matchDict = {}; - // TODO: 1st-party hostnames are already available somewhere on the - // caller's side, reuse this information, for performance purpose. - var firstPartyList = uriTools.allHostnamesFromHostname(firstParty); - var firstPartyDict = {}; - var i = 0, j; - while ( firstParty = firstPartyList[i++] ) { - firstPartyDict[firstParty] = true; - presets = this.firstPartyDict[firstParty]; - if ( !presets ) { - continue; + var i, j; + + presets = this.hostnameTo1stPartyPresetMap[firstParty]; + if ( !presets ) { + presets = this.hostnameTo1stPartyPresetMap[HTTPSB.domainScopeKeyFromHostname(firstParty)]; + } + + if ( presets ) { + if ( presets instanceof HTTPSB.PresetRecipe ) { + presets = [presets]; } j = 0; while ( preset = presets[j++] ) { @@ -155,20 +137,30 @@ HTTPSB.PresetManager.prototype.findMatches = function(firstParty, thirdParties) matchDict[preset.id] = true; } } + // TODO: Ideally, only the hostnames for which there was effectively a // request should be in the input collection, for performance purpose. + var hostnameTo1stPartyPresetMap = {}; + var firstPartyList = uriTools.allHostnamesFromHostname(firstParty); + i = 0; + while ( firstParty = firstPartyList[i++] ) { + hostnameTo1stPartyPresetMap[firstParty] = true; + } for ( var thirdParty in thirdParties ) { if ( !thirdParties.hasOwnProperty(thirdParty) ) { continue; } // Skip 3rd-parties same as 1st-party - if ( firstPartyDict[thirdParty] ) { + if ( hostnameTo1stPartyPresetMap[thirdParty] ) { continue; } - presets = this.thirdPartyDict[thirdParty]; + presets = this.hostnameTo3rdPartyPresetMap[thirdParty]; if ( !presets ) { continue; } + if ( presets instanceof HTTPSB.PresetRecipe ) { + presets = [presets]; + } j = 0; while ( preset = presets[j++] ) { if ( matchDict[preset.id] ) { @@ -183,6 +175,89 @@ HTTPSB.PresetManager.prototype.findMatches = function(firstParty, thirdParties) /******************************************************************************/ +HTTPSB.PresetManager.prototype.applyToScope = function(scopeKey, presetId) { + var preset = this.presets[presetId]; + if ( !preset ) { + return; + } + + if ( preset.barrier ) { + return; + } + preset.barrier++; + + // Process required preset recipes + if ( preset.firstParty && preset.requires ) { + var i, other; + if ( typeof preset.requires === 'string' ) { + if ( other = this.firstPartyFromName(preset.requires) ) { + this.applyToScope(scopeKey, other.id); + } + } else { + i = preset.requires.length; + while ( i-- ) { + if ( other = this.firstPartyFromName(preset.requires[i]) ) { + this.applyToScope(scopeKey, other.id); + } + } + } + } + + var httpsb = HTTPSB; + var rules, ruleKey, pos; + + // Unscoped rules + rules = preset.whitelist; + for ( ruleKey in rules ) { + if ( !rules.hasOwnProperty(ruleKey) ) { + continue; + } + pos = ruleKey.indexOf('|'); + httpsb.whitelistTemporarily(scopeKey, ruleKey.slice(0, pos), ruleKey.slice(pos + 1)); + } + + // Scoped rules + var scopes = preset.scopes; + for ( scopeKey in scopes ) { + if ( !scopes.hasOwnProperty(scopeKey) ) { + continue; + } + if ( httpsb.temporaryScopeExists(scopeKey) === false ) { + httpsb.createTemporaryScopeFromScopeKey(scopeKey); + httpsb.whitelistTemporarily(scopeKey, 'main_frame', '*'); + httpsb.whitelistTemporarily(scopeKey, 'stylesheet', '*'); + httpsb.whitelistTemporarily(scopeKey, 'image', '*'); + httpsb.copyTemporaryBlackRules(scopeKey, '*'); + } + rules = scopes[scopeKey].whitelist; + for ( ruleKey in rules ) { + if ( !rules.hasOwnProperty(ruleKey) ) { + continue; + } + pos = ruleKey.indexOf('|'); + httpsb.whitelistTemporarily(scopeKey, ruleKey.slice(0, pos), ruleKey.slice(pos + 1)); + } + // Remove site-level scopes which could occlude domain-level scope. + if ( httpsb.isDomainScopeKey(scopeKey) ) { + httpsb.revealTemporaryDomainScope(scopeKey); + } + } + + preset.barrier--; +}; + +/******************************************************************************/ + +HTTPSB.PresetManager.prototype.applyFromPresetName = function(presetName) { + var preset = httpsb.presetManager.firstPartyFromName(presetName); + if ( !preset ) { + return; + } + httpsb.presetManager.applyToScope('*', preset.id); +}; + +/******************************************************************************/ + HTTPSB.PresetManager.prototype.typeMapper = { '*': '*', 'cookie': 'cookie', @@ -246,6 +321,7 @@ HTTPSB.PresetManager.prototype.parseEntry = function(entry) { fvalue = ''; } } + // Remove quotes if any. fvalue = fvalue.replace(/^(["']?)(.*)\1$/, '$2'); // Skip empty lines @@ -263,13 +339,19 @@ HTTPSB.PresetManager.prototype.parseEntry = function(entry) { context = contextStack.join('/'); switch ( context ) { + case 'preset/requires': + break; case 'preset/scope': if ( fkey === 'whitelist' ) { contextStack.push(fkey); } break; case 'preset': - if ( fkey === 'facode' || fkey === 'keys' || fkey === 'scope' || fkey === 'whitelist' ) { + if ( fkey === 'facode' || + fkey === 'keys' || + fkey === 'requires' || + fkey === 'scope' || + fkey === 'whitelist' ) { contextStack.push(fkey); } break; @@ -296,6 +378,17 @@ HTTPSB.PresetManager.prototype.parseEntry = function(entry) { p.keys[fvalue] = true; } break; + case 'preset/requires': + if ( fvalue !== '' ) { + if ( p.requires === null ) { + p.requires = fvalue; + } else if ( typeof p.requires === 'string') { + p.requires = [p.requires, fvalue]; + } else { + p.requires.push(fvalue); + } + } + break; case 'preset/scope': scopeKey = fvalue; break; diff --git a/js/rulemanager.js b/js/rulemanager.js index 717502e..20cdb8a 100644 --- a/js/rulemanager.js +++ b/js/rulemanager.js @@ -577,15 +577,37 @@ function toggleDeleteRule(event) { /******************************************************************************/ function commitAll() { - var deleteCount = $('.scope.todelete .rule,.rule.todelete').length; - if ( deleteCount ) { - var prompt = $('#confirmRemoveAll').text().replace('{{deleteCount}}', deleteCount); - if ( !confirm(prompt) ) { - $('.scope').removeClass('todelete'); - return; - } + if ( !confirmDeleteAll() ) { + return false; } + deleteAll(); + + // Persist whatever is left + var httpsb = getHTTPSB(); + httpsb.commitPermissions(true); + renderAll(); + + return true; +} + +/******************************************************************************/ + +function revertAll() { + var httpsb = getHTTPSB(); + httpsb.revertAllRules(); + renderAll(); +} + +/******************************************************************************/ + +function markAllForDeletion() { + $('.scope').addClass('todelete'); + updateButtons(); +} + +/******************************************************************************/ +function deleteAll() { var httpsb = getHTTPSB(); var i; var liScope, scopeKey; @@ -607,13 +629,6 @@ function commitAll() { liScope.remove(); } - // Delete rules marked for deletion - var dontTouch = { - '*|white|stylesheet|*': true, - '*|white|image|*': true, - '*|black|sub_frame|*': true, - 'chromium-behind-the-scene|white|*|*': true - }; liRules = $('.scope.todelete .rule,.rule.todelete'); i = liRules.length; while ( i-- ) { @@ -626,10 +641,6 @@ function commitAll() { pos = rule.indexOf('|'); type = rule.slice(0, pos); hostname = rule.slice(pos + 1); - // rhill 2014-01-29: Do not delete out-of-the-box rules. - if ( dontTouch[scopeKey + '|' + listKey + '|' + rule] ) { - continue; - } httpsb.removeTemporaryRule( scopeKey, listKey, @@ -637,24 +648,38 @@ function commitAll() { hostname ); } - - // Persist whatever is left - httpsb.commitPermissions(true); - renderAll(); } /******************************************************************************/ -function revertAll() { - var httpsb = getHTTPSB(); - httpsb.revertAllRules(); - renderAll(); +function confirmDeleteAll() { + var deleteCount = $('.scope.todelete .rule,.rule.todelete').length; + if ( deleteCount ) { + var prompt = $('#confirmRemoveAll').text().replace('{{deleteCount}}', deleteCount); + if ( !confirm(prompt) ) { + $('.scope').removeClass('todelete'); + return false; + } + } + return true; } /******************************************************************************/ -function removeAll() { +function resetAll() { $('.scope').addClass('todelete'); + if ( !confirmDeleteAll() ) { + return false; + } + deleteAll(); + var httpsb = getHTTPSB(); + httpsb.whitelistTemporarily('*', 'main_frame', '*'); + httpsb.whitelistTemporarily('*', 'stylesheet', '*'); + httpsb.whitelistTemporarily('*', 'image', '*'); + httpsb.blacklistTemporarily('*', 'sub_frame', '*'); + httpsb.whitelistTemporarily(httpsb.behindTheSceneScopeKey, '*', '*'); + httpsb.commitPermissions(true); + renderAll(); updateButtons(); } @@ -705,7 +730,7 @@ function updateButtons() { var notOneDeletion = $('.todelete').length === 0; $('#commitAll').prop("disabled", notOneTemporary && notOneDeletion); $('#revertAll').prop("disabled", notOneTemporary && notOneDeletion); - $('#removeAll').prop("disabled", $('.scope:not(.todelete)').length === 0); + $('#markAllForDeletion').prop("disabled", $('.scope:not(.todelete)').length === 0); } /******************************************************************************/ @@ -713,7 +738,8 @@ function updateButtons() { $(function() { $('#commitAll').on('click', commitAll); $('#revertAll').on('click', revertAll); - $('#removeAll').on('click', removeAll); + $('#markAllForDeletion').on('click', markAllForDeletion); + $('#resetAll').on('click', resetAll); $('#backup').on('click', saveAllToFile); $('#restore').on('click', restoreFromFile); diff --git a/js/start.js b/js/start.js index 1d064e3..2e2a06b 100644 --- a/js/start.js +++ b/js/start.js @@ -51,9 +51,9 @@ function onUpdatedTabsHandler(tabId, changeInfo, tab) { // better than building a state snapshot dynamically when requests are // recorded, because here we are not afflicted by the browser cache // mechanism. - var pageStats = pageStatsFromPageUrl(pageURL); + var pageStats = HTTPSB.pageStatsFromPageUrl(pageURL); if ( pageStats ) { - pageStats.state = computeTabState(tabId); + pageStats.state = HTTPSB.computeTabState(tabId); } updateContextMenu(); @@ -69,7 +69,7 @@ function onRemovedTabHandler(tabId) { return; } - unbindTabFromPageStats(tabId); + HTTPSB.unbindTabFromPageStats(tabId); } chrome.tabs.onRemoved.addListener(onRemovedTabHandler); @@ -83,20 +83,18 @@ chrome.tabs.onActivated.addListener(updateContextMenu) // Bind a top URL to a specific tab function onBeforeNavigateCallback(details) { - if ( details.url.search(/^https?:\/\//) < 0 ) { + // Don't bind to a subframe + if ( details.frameId > 0 ) { return; } + // TODO: I think this should be removed and let the core code handle + // this. if ( HTTPSB.excludeRegex.test(details.url) ) { return; } - // Don't bind to a subframe - if ( details.frameId > 0 ) { - return; - } - // console.debug('onBeforeNavigateCallback() > binding "%s" to tab %d', details.url, details.tabId); - bindTabToPageStats(details.tabId, uriTools.normalizeURI(details.url)); + HTTPSB.bindTabToPageStats(details.tabId, uriTools.normalizeURI(details.url)); } chrome.webNavigation.onBeforeNavigate.addListener(onBeforeNavigateCallback); @@ -114,7 +112,7 @@ load(); // https://github.com/gorhill/httpswitchboard/issues/67 (function(tabId, pageUrl) { - var pageStats = createPageStats(pageUrl); + var pageStats = HTTPSB.createPageStats(pageUrl); HTTPSB.pageUrlToTabId[pageUrl] = tabId; HTTPSB.tabIdToPageUrl[tabId] = pageUrl; })(HTTPSB.behindTheSceneTabId, HTTPSB.behindTheSceneURL); @@ -130,7 +128,7 @@ load(); var tab; while ( i-- ) { tab = tabs[i]; - bindTabToPageStats(tab.id, uriTools.normalizeURI(tab.url)); + HTTPSB.bindTabToPageStats(tab.id, uriTools.normalizeURI(tab.url)); } // Tabs are now bound to url stats stores, therefore it is now safe // to handle net traffic. @@ -185,18 +183,10 @@ function onInstalledHandler(details) { var httpsb = HTTPSB; // rhill 2014-01-29: Opera requires that Youtube works out-of-the-box. // Actually, why not do that for everybody, not just Opera. - // TODO: Evaluate having presets which self-apply at *install* time. - var preset = httpsb.presetManager.firstPartyFromHostname('www.youtube.com'); - if ( !preset ) { - return; + if ( httpsb.isOpera() ) { + httpsb.presetManager.applyFromPresetName('Youtube'); + httpsb.commitPermissions(true); } - var scopeKey = httpsb.siteScopeKeyFromURL('http://www.youtube.com/'); - httpsb.createTemporaryScopeFromScopeKey(scopeKey); - preset.applyToScope(scopeKey); - - // More presets? - - httpsb.commitPermissions(true); } chrome.runtime.onInstalled.addListener(onInstalledHandler); diff --git a/js/tab.js b/js/tab.js index cc92d9f..20ab6c8 100644 --- a/js/tab.js +++ b/js/tab.js @@ -446,7 +446,7 @@ function garbageCollectStalePageStatsWithNoTabsCallback(tabs) { if ( pageUrl === httpsb.behindTheSceneURL ) { continue; } - tabId = tabIdFromPageUrl(pageUrl); + tabId = httpsb.tabIdFromPageUrl(pageUrl); pageStats = httpsb.pageStats[pageUrl]; if ( !visibleTabs[tabId] && !pageStats.visible ) { cookieHunter.removePageCookiesAsync(pageStats); @@ -456,7 +456,7 @@ function garbageCollectStalePageStatsWithNoTabsCallback(tabs) { } pageStats.visible = !!visibleTabs[tabId]; if ( !pageStats.visible ) { - unbindTabFromPageStats(tabId); + httpsb.unbindTabFromPageStats(tabId); } } } @@ -493,96 +493,80 @@ asyncJobQueue.add('gcPageStats', null, garbageCollectStalePageStatsCallback, 10 /******************************************************************************/ -// Check if a page url stats store exists - -function pageStatsExists(pageUrl) { - return !!pageStatsFromPageUrl(pageUrl); -} - -/******************************************************************************/ - // Create a new page url stats store (if not already present) -function createPageStats(pageUrl) { +HTTPSB.createPageStats = function(pageUrl) { // do not create stats store for urls which are of no interest if ( pageUrl.search(/^https?:\/\//) !== 0 ) { return undefined; } - var httpsb = HTTPSB; - var pageStats = httpsb.pageStats[pageUrl]; + var pageStats = this.pageStats[pageUrl]; if ( !pageStats ) { pageStats = PageStatsEntry.factory(pageUrl); // These counters are used so that icon presents an overview of how // much allowed/blocked. pageStats.perLoadAllowedRequestCount = pageStats.perLoadBlockedRequestCount = 0; - httpsb.pageStats[pageUrl] = pageStats; + this.pageStats[pageUrl] = pageStats; } else if ( pageStats.pageUrl !== pageUrl ) { pageStats.init(pageUrl); } return pageStats; -} +}; /******************************************************************************/ // Create an entry for the tab if it doesn't exist -function bindTabToPageStats(tabId, pageURL) { - var pageStats = createPageStats(pageURL); - if ( !pageStats ) { - return undefined; - } +HTTPSB.bindTabToPageStats = function(tabId, pageURL) { + var pageStats = this.createPageStats(pageURL); + + // console.debug('HTTP Switchboard> HTTPSB.bindTabToPageStats(): dispatching traffic in tab id %d to url stats store "%s"', tabId, pageUrl); - // console.debug('bindTabToPageStats > dispatching traffic in tab id %d to url stats store "%s"', tabId, pageUrl); // rhill 2013-11-24: Never ever rebind chromium-behind-the-scene // virtual tab. // https://github.com/gorhill/httpswitchboard/issues/67 - if ( tabId !== HTTPSB.behindTheSceneTabId ) { - unbindTabFromPageStats(tabId); - HTTPSB.pageUrlToTabId[pageURL] = tabId; - HTTPSB.tabIdToPageUrl[tabId] = pageURL; + if ( tabId !== this.behindTheSceneTabId ) { + this.unbindTabFromPageStats(tabId); + + // rhill 2014-02-08: Do not create an entry if no page store + // exists (like when visiting about:blank) + // https://github.com/gorhill/httpswitchboard/issues/186 + if ( pageStats ) { + this.pageUrlToTabId[pageURL] = tabId; + this.tabIdToPageUrl[tabId] = pageURL; + } } return pageStats; -} +}; -function unbindTabFromPageStats(tabId) { - var httpsb = HTTPSB; - var pageUrl = httpsb.tabIdToPageUrl[tabId]; +HTTPSB.unbindTabFromPageStats = function(tabId) { + var pageUrl = this.tabIdToPageUrl[tabId]; if ( pageUrl ) { - delete httpsb.pageUrlToTabId[pageUrl]; + delete this.pageUrlToTabId[pageUrl]; } - delete httpsb.tabIdToPageUrl[tabId]; -} - -/******************************************************************************/ - -function urlFromReqKey(reqKey) { - return reqKey.slice(0, reqKey.indexOf('#')); -} - -function typeFromReqKey(reqKey) { - return reqKey.slice(reqKey.indexOf('#') + 1); -} + delete this.tabIdToPageUrl[tabId]; +}; /******************************************************************************/ // Log a request -function recordFromTabId(tabId, type, url, blocked) { - var pageStats = pageStatsFromTabId(tabId); +HTTPSB.recordFromTabId = function(tabId, type, url, blocked) { + var pageStats = this.pageStatsFromTabId(tabId); if ( pageStats ) { pageStats.recordRequest(type, url, blocked); } -} +}; -function recordFromPageUrl(pageUrl, type, url, blocked) { - var pageStats = pageStatsFromPageUrl(pageUrl); +HTTPSB.recordFromPageUrl = function(pageUrl, type, url, blocked) { + var pageStats = this.pageStatsFromPageUrl(pageUrl); if ( pageStats ) { pageStats.recordRequest(type, url, blocked); } -} +}; /******************************************************************************/ @@ -590,12 +574,13 @@ function recordFromPageUrl(pageUrl, type, url, blocked) { // rhill 2013-10-23: revised to avoid closures. function smartReloadExistingTabsCallback(chromeTabs) { + var httpsb = HTTPSB; var tabId; var i = chromeTabs.length; while ( i-- ) { tabId = chromeTabs[i].id; - if ( tabExists(tabId) ) { - smartReloadTab(tabId); + if ( httpsb.tabExists(tabId) ) { + httpsb.smartReloadTab(tabId); } } } @@ -612,10 +597,10 @@ function smartReloadTabs() { // Reload content of a tab -function smartReloadTab(tabId) { - var pageStats = pageStatsFromTabId(tabId); +HTTPSB.smartReloadTab = function(tabId) { + var pageStats = this.pageStatsFromTabId(tabId); if ( !pageStats || pageStats.ignore ) { - //console.error('HTTP Switchboard > smartReloadTab > page stats for tab id %d not found', tabId); + //console.error('HTTP Switchboard> HTTPSB.smartReloadTab(): page stats for tab id %d not found', tabId); return; } @@ -623,7 +608,7 @@ function smartReloadTab(tabId) { // unblocked. var blockRule; var oldState = pageStats.state; - var newState = computeTabState(tabId); + var newState = this.computeTabState(tabId); var mustReload = false; for ( blockRule in oldState ) { if ( !oldState.hasOwnProperty(blockRule) ) { @@ -632,7 +617,7 @@ function smartReloadTab(tabId) { // General rule, reload... // If something previously blocked is no longer blocked. if ( !newState[blockRule] ) { - // console.debug('smartReloadTab() > will reload because "%s" is no longer blocked', blockRule); + // console.debug('HTTP Switchboard> HTTPSB.smartReloadTab(): will reload because "%s" is no longer blocked', blockRule); mustReload = true; break; } @@ -655,7 +640,7 @@ function smartReloadTab(tabId) { continue; } if ( !oldState[blockRule] ) { - // console.debug('smartReloadTab() > will reload because "%s" is now blocked', blockRule); + // console.debug('HTTP Switchboard> HTTPSB.smartReloadTab(): will reload because "%s" is now blocked', blockRule); mustReload = true; break; } @@ -666,7 +651,7 @@ function smartReloadTab(tabId) { chrome.tabs.reload(tabId); } // pageStats.state = newState; -} +}; /******************************************************************************/ @@ -676,23 +661,22 @@ function smartReloadTab(tabId) { // `chrome-devtools://devtools/devtools.html` // etc. -function tabExists(tabId) { - return !!pageUrlFromTabId(tabId); -} +HTTPSB.tabExists = function(tabId) { + return !!this.pageUrlFromTabId(tabId); +}; /******************************************************************************/ -function computeTabState(tabId) { - var pageStats = pageStatsFromTabId(tabId); +HTTPSB.computeTabState = function(tabId) { + var pageStats = this.pageStatsFromTabId(tabId); if ( !pageStats ) { - //console.error('HTTP Switchboard > computeTabState > page stats for tab id %d not found', tabId); + //console.error('HTTP Switchboard> HTTPSB.computeTabState(): page stats for tab id %d not found', tabId); return {}; } // Go through all recorded requests, apply filters to create state // It is a critical error for a tab to not be defined here - var httpsb = HTTPSB; var pageURL = pageStats.pageUrl; - var scopeKey = httpsb.temporaryScopeKeyFromPageURL(pageURL); + var scopeKey = this.temporaryScopeKeyFromPageURL(pageURL); var requestDict = pageStats.requests.getRequestDict(); var computedState = {}; var hostname, type; @@ -709,52 +693,52 @@ function computeTabState(tabId) { // `stylesheet` or `other`? Depends of domain of request. // https://github.com/gorhill/httpswitchboard/issues/85 type = PageStatsRequests.typeFromRequestKey(reqKey); - if ( httpsb.blacklistedFromScopeKey(scopeKey, type, hostname) ) { + if ( this.blacklistedFromScopeKey(scopeKey, type, hostname) ) { computedState[type + '|' + hostname] = true; } } return computedState; -} +}; /******************************************************************************/ -function tabIdFromPageUrl(pageUrl) { - return HTTPSB.pageUrlToTabId[pageUrl]; -} +HTTPSB.tabIdFromPageUrl = function(pageUrl) { + return this.pageUrlToTabId[pageUrl]; +}; -function tabIdFromPageStats(pageStats) { - return tabIdFromPageUrl(pageStats.pageUrl); -} +HTTPSB.tabIdFromPageStats = function(pageStats) { + return this.tabIdFromPageUrl(pageStats.pageUrl); +}; -function pageUrlFromTabId(tabId) { - return HTTPSB.tabIdToPageUrl[tabId]; -} +HTTPSB.pageUrlFromTabId = function(tabId) { + return this.tabIdToPageUrl[tabId]; +}; -function pageUrlFromPageStats(pageStats) { +HTTPSB.pageUrlFromPageStats = function(pageStats) { if ( pageStats ) { return pageStats.getPageURL(); } return undefined; -} +}; -function pageStatsFromTabId(tabId) { - var pageUrl = HTTPSB.tabIdToPageUrl[tabId]; +HTTPSB.pageStatsFromTabId = function(tabId) { + var pageUrl = this.tabIdToPageUrl[tabId]; if ( pageUrl ) { - return HTTPSB.pageStats[pageUrl]; + return this.pageStats[pageUrl]; } return undefined; -} +}; -function pageStatsFromPageUrl(pageUrl) { - return HTTPSB.pageStats[pageUrl]; -} +HTTPSB.pageStatsFromPageUrl = function(pageUrl) { + return this.pageStats[pageUrl]; +}; /******************************************************************************/ -function forceReload(pageURL) { - var tabId = tabIdFromPageUrl(pageURL); +HTTPSB.forceReload = function(pageURL) { + var tabId = this.tabIdFromPageUrl(pageURL); if ( tabId ) { chrome.tabs.reload(tabId, { bypassCache: true }); } -} +}; diff --git a/js/traffic.js b/js/traffic.js index 0031cfc..4b647af 100644 --- a/js/traffic.js +++ b/js/traffic.js @@ -102,7 +102,7 @@ background: #c00; \ function onBeforeRequestHandler(details) { // quickProfiler.start(); - // console.debug('onBeforeRequestHandler()> "%s"', details.url); + // console.debug('onBeforeRequestHandler()> "%s": %o', details.url, details); var canEvaluate = true; var httpsb = HTTPSB; @@ -149,7 +149,7 @@ function onBeforeRequestHandler(details) { var isSubFrame = type === 'sub_frame'; var isMainFrame = type === 'main_frame'; var isWebPage = isMainFrame && details.parentFrameId < 0; - var pageStats = pageStatsFromTabId(tabId); + var pageStats = httpsb.pageStatsFromTabId(tabId); // rhill 2013-12-16: Do not interfere with apps. For now the heuristic is: // If we have a `sub_frame` and no pageStats store, this is an app. @@ -157,10 +157,10 @@ function onBeforeRequestHandler(details) { var isApp = isSubFrame && !pageStats; if ( isWebPage || isApp ) { - bindTabToPageStats(tabId, requestURL); + httpsb.bindTabToPageStats(tabId, requestURL); } - pageStats = pageStatsFromTabId(tabId); + pageStats = httpsb.pageStatsFromTabId(tabId); // rhill 2013-12-16: I don't remember... Can pageStats still be nil at // this point? @@ -175,7 +175,7 @@ function onBeforeRequestHandler(details) { } hostname = uriTools.hostnameFromURI(requestURL); - pageURL = pageUrlFromPageStats(pageStats); + pageURL = httpsb.pageUrlFromPageStats(pageStats); // rhill 2013-12-15: // Try to transpose generic `other` category into something more @@ -275,7 +275,7 @@ function onBeforeSendHeadersHandler(details) { // rhill 2013-12-16: do not interfere with apps. // https://github.com/gorhill/httpswitchboard/issues/91 - var pageStats = pageStatsFromTabId(tabId); + var pageStats = httpsb.pageStatsFromTabId(tabId); if ( pageStats && pageStats.ignore ) { return; } @@ -283,7 +283,7 @@ function onBeforeSendHeadersHandler(details) { // Any cookie in there? var ut = uriTools; var hostname = ut.hostnameFromURI(details.url); - var pageURL = pageUrlFromTabId(tabId); + var pageURL = httpsb.pageUrlFromTabId(tabId); var blacklistCookie = httpsb.blacklisted(pageURL, 'cookie', hostname); var processReferer = httpsb.userSettings.processReferer; @@ -375,12 +375,12 @@ function onHeadersReceivedHandler(details) { // to not be able to lookup the pageStats. So let the code here bind // the page to a tab if not done yet. // https://github.com/gorhill/httpswitchboard/issues/75 + var httpsb = HTTPSB; var tabId = details.tabId; if ( tabId >= 0 && isWebPage ) { - bindTabToPageStats(tabId, requestURL); + httpsb.bindTabToPageStats(tabId, requestURL); } - var pageStats = pageStatsFromTabId(tabId); - var httpsb = HTTPSB; + var pageStats = httpsb.pageStatsFromTabId(tabId); var headers = details.responseHeaders; if ( isWebPage ) { @@ -442,7 +442,7 @@ function onHeadersReceivedHandler(details) { // request, use global scope to evaluate whether it should be blocked // or allowed. // https://github.com/gorhill/httpswitchboard/issues/75 - var pageURL = pageStats ? pageUrlFromPageStats(pageStats) : '*'; + var pageURL = pageStats ? httpsb.pageUrlFromPageStats(pageStats) : '*'; if ( httpsb.whitelisted(pageURL, 'script', requestHostname) ) { return; } @@ -487,7 +487,8 @@ function onErrorOccurredHandler(details) { return; } - var pageStats = pageStatsFromPageUrl(details.url); + var httpsb = HTTPSB; + var pageStats = httpsb.pageStatsFromPageUrl(details.url); if ( !pageStats ) { return; } @@ -496,7 +497,6 @@ function onErrorOccurredHandler(details) { // emit an error when a web page redirects apparently endlessly, so // we need to unravel and report all these redirects upon error. // https://github.com/gorhill/httpswitchboard/issues/171 - var httpsb = HTTPSB; var requestURL = uriTools.normalizeURI(details.url); var mainFrameStack = [requestURL]; var destinationURL = requestURL; @@ -551,6 +551,8 @@ function startWebRequestHandler(from) { [ "blocking" ] ); + console.log('HTTP Switchboard> Beginning to intercept net requests at %s', (new Date()).toISOString()); + chrome.webRequest.onBeforeSendHeaders.addListener( onBeforeSendHeadersHandler, { diff --git a/rulemanager.html b/rulemanager.html index 447fa35..3cf3e74 100644 --- a/rulemanager.html +++ b/rulemanager.html @@ -12,7 +12,8 @@

HTTP Switchboard — Rule manager

- + +