From d0738c0835338a15683b9dfffd12b670f513c3f1 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Tue, 31 Dec 2019 16:36:51 -0500 Subject: [PATCH] Visually distinguish canonical names in popup panel Further fine-tuning support for canonical names. Aliased canonical names will be rendered blue in the dynamic filtering pane of the popup panel. --- platform/chromium/vapi-background.js | 2 + platform/firefox/vapi-webrequest.js | 27 ++++---- src/css/popup.css | 3 + src/js/background.js | 2 +- src/js/messaging.js | 94 ++++++++++++++-------------- src/js/popup.js | 6 ++ src/js/traffic.js | 6 +- 7 files changed, 79 insertions(+), 61 deletions(-) diff --git a/platform/chromium/vapi-background.js b/platform/chromium/vapi-background.js index 2f0669518..fd13d8b9c 100644 --- a/platform/chromium/vapi-background.js +++ b/platform/chromium/vapi-background.js @@ -1200,6 +1200,8 @@ vAPI.Net = class { denormalizeTypes(types) { return types; } + canonicalNameFromHostname(/* hn */) { + } addListener(which, clientListener, filters, options) { const actualFilters = this.denormalizeFilters(filters); const actualListener = this.makeNewListenerProxy(clientListener); diff --git a/platform/firefox/vapi-webrequest.js b/platform/firefox/vapi-webrequest.js index 8b182f883..3dedbd690 100644 --- a/platform/firefox/vapi-webrequest.js +++ b/platform/firefox/vapi-webrequest.js @@ -65,9 +65,9 @@ this.cnameIgnore1stParty = true; this.cnameIgnoreExceptions = true; this.cnameIgnoreRootDocument = true; - this.cnameMaxTTL = 60; + this.cnameMaxTTL = 120; this.cnameReplayFullURL = false; - this.cnameTimer = undefined; + this.cnameFlushTime = Date.now() + this.cnameMaxTTL * 60000; this.cnameUncloak = browser.dns instanceof Object; } setOptions(options) { @@ -81,6 +81,7 @@ this.cnameMaxTTL = options.cnameMaxTTL || 120; this.cnameReplayFullURL = options.cnameReplayFullURL === true; this.cnames.clear(); this.cnames.set('', ''); + this.cnameFlushTime = Date.now() + this.cnameMaxTTL * 60000; } normalizeDetails(details) { if ( mustPunycode && !reAsciiHostname.test(details.url) ) { @@ -130,6 +131,12 @@ } return Array.from(out); } + canonicalNameFromHostname(hn) { + const cn = this.cnames.get(hn); + if ( cn !== undefined && cn !== '' ) { + return cn; + } + } processCanonicalName(hn, cn, details) { const hnBeg = details.url.indexOf(hn); if ( hnBeg === -1 ) { return; } @@ -149,6 +156,13 @@ return super.onBeforeSuspendableRequest(details); } recordCanonicalName(hn, record) { + if ( (this.cnames.size & 0b111111) === 0 ) { + const now = Date.now(); + if ( now >= this.cnameFlushTime ) { + this.cnames.clear(); this.cnames.set('', ''); + this.cnameFlushTime = now + this.cnameMaxTTL * 60000; + } + } let cname = typeof record.canonicalName === 'string' && record.canonicalName !== hn @@ -169,15 +183,6 @@ cname = ''; } this.cnames.set(hn, cname); - if ( this.cnameTimer === undefined ) { - this.cnameTimer = self.setTimeout( - ( ) => { - this.cnameTimer = undefined; - this.cnames.clear(); this.cnames.set('', ''); - }, - this.cnameMaxTTL * 60000 - ); - } return cname; } regexFromStrList(list) { diff --git a/src/css/popup.css b/src/css/popup.css index 1e056a97d..4dd6ebe99 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -281,6 +281,9 @@ body[dir="rtl"] #tooltip { padding-right: 2px; width: calc(100% - 4em); } +#firewallContainer > div.isCname > span:first-of-type { + color: mediumblue; + } #firewallContainer > div > span:first-of-type > sup { color: #666; display: none; diff --git a/src/js/background.js b/src/js/background.js index 86ea12ee1..3c92cb492 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -50,7 +50,7 @@ const µBlock = (( ) => { // jshint ignore:line cnameIgnore1stParty: true, cnameIgnoreExceptions: true, cnameIgnoreRootDocument: true, - cnameMaxTTL: 60, + cnameMaxTTL: 120, cnameReplayFullURL: false, cnameUncloak: true, consoleLogLevel: 'unset', diff --git a/src/js/messaging.js b/src/js/messaging.js index 4d7d6f960..8cba8e049 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -187,78 +187,78 @@ vAPI.messaging.setup(onMessage); const µb = µBlock; -const getHostnameDict = function(hostnameToCountMap) { - const r = Object.create(null); - const domainFromHostname = µb.URI.domainFromHostname; - // Note: destructuring assignment not supported before Chromium 49. +const getHostnameDict = function(hostnameToCountMap, out) { + const hnDict = Object.create(null); + const cnSet = []; for ( const [ hostname, hnCounts ] of hostnameToCountMap ) { - if ( r[hostname] !== undefined ) { continue; } - const domain = domainFromHostname(hostname) || hostname; + if ( hnDict[hostname] !== undefined ) { continue; } + const domain = vAPI.domainFromHostname(hostname) || hostname; const dnCounts = hostnameToCountMap.get(domain) || 0; let blockCount = dnCounts & 0xFFFF; let allowCount = dnCounts >>> 16 & 0xFFFF; - if ( r[domain] === undefined ) { - r[domain] = { - domain: domain, - blockCount: blockCount, - allowCount: allowCount, + if ( hnDict[domain] === undefined ) { + hnDict[domain] = { + domain, + blockCount, + allowCount, totalBlockCount: blockCount, - totalAllowCount: allowCount + totalAllowCount: allowCount, }; + const cname = vAPI.net.canonicalNameFromHostname(domain); + if ( cname !== undefined ) { + cnSet.push(cname); + } } - const domainEntry = r[domain]; + const domainEntry = hnDict[domain]; blockCount = hnCounts & 0xFFFF; allowCount = hnCounts >>> 16 & 0xFFFF; domainEntry.totalBlockCount += blockCount; domainEntry.totalAllowCount += allowCount; if ( hostname === domain ) { continue; } - r[hostname] = { - domain: domain, - blockCount: blockCount, - allowCount: allowCount, + hnDict[hostname] = { + domain, + blockCount, + allowCount, totalBlockCount: 0, totalAllowCount: 0, }; + const cname = vAPI.net.canonicalNameFromHostname(hostname); + if ( cname !== undefined ) { + cnSet.push(cname); + } } - return r; + out.hostnameDict = hnDict; + out.cnameSet = cnSet; }; const getFirewallRules = function(srcHostname, desHostnames) { - var r = {}; - var df = µb.sessionFirewall; - r['/ * *'] = df.lookupRuleData('*', '*', '*'); - r['/ * image'] = df.lookupRuleData('*', '*', 'image'); - r['/ * 3p'] = df.lookupRuleData('*', '*', '3p'); - r['/ * inline-script'] = df.lookupRuleData('*', '*', 'inline-script'); - r['/ * 1p-script'] = df.lookupRuleData('*', '*', '1p-script'); - r['/ * 3p-script'] = df.lookupRuleData('*', '*', '3p-script'); - r['/ * 3p-frame'] = df.lookupRuleData('*', '*', '3p-frame'); - if ( typeof srcHostname !== 'string' ) { return r; } + const out = {}; + const df = µb.sessionFirewall; + out['/ * *'] = df.lookupRuleData('*', '*', '*'); + out['/ * image'] = df.lookupRuleData('*', '*', 'image'); + out['/ * 3p'] = df.lookupRuleData('*', '*', '3p'); + out['/ * inline-script'] = df.lookupRuleData('*', '*', 'inline-script'); + out['/ * 1p-script'] = df.lookupRuleData('*', '*', '1p-script'); + out['/ * 3p-script'] = df.lookupRuleData('*', '*', '3p-script'); + out['/ * 3p-frame'] = df.lookupRuleData('*', '*', '3p-frame'); + if ( typeof srcHostname !== 'string' ) { return out; } - r['. * *'] = df.lookupRuleData(srcHostname, '*', '*'); - r['. * image'] = df.lookupRuleData(srcHostname, '*', 'image'); - r['. * 3p'] = df.lookupRuleData(srcHostname, '*', '3p'); - r['. * inline-script'] = df.lookupRuleData(srcHostname, + out['. * *'] = df.lookupRuleData(srcHostname, '*', '*'); + out['. * image'] = df.lookupRuleData(srcHostname, '*', 'image'); + out['. * 3p'] = df.lookupRuleData(srcHostname, '*', '3p'); + out['. * inline-script'] = df.lookupRuleData(srcHostname, '*', 'inline-script' ); - r['. * 1p-script'] = df.lookupRuleData(srcHostname, '*', '1p-script'); - r['. * 3p-script'] = df.lookupRuleData(srcHostname, '*', '3p-script'); - r['. * 3p-frame'] = df.lookupRuleData(srcHostname, '*', '3p-frame'); + out['. * 1p-script'] = df.lookupRuleData(srcHostname, '*', '1p-script'); + out['. * 3p-script'] = df.lookupRuleData(srcHostname, '*', '3p-script'); + out['. * 3p-frame'] = df.lookupRuleData(srcHostname, '*', '3p-frame'); for ( const desHostname in desHostnames ) { - r[`/ ${desHostname} *`] = df.lookupRuleData( - '*', - desHostname, - '*' - ); - r[`. ${desHostname} *`] = df.lookupRuleData( - srcHostname, - desHostname, - '*' - ); + out[`/ ${desHostname} *`] = df.lookupRuleData('*', desHostname, '*'); + out[`. ${desHostname} *`] = df.lookupRuleData(srcHostname, desHostname, '*'); } - return r; + return out; }; const popupDataFromTabId = function(tabId, tabTitle) { @@ -304,7 +304,7 @@ const popupDataFromTabId = function(tabId, tabTitle) { r.pageBlockedRequestCount = pageStore.perLoadBlockedRequestCount; r.pageAllowedRequestCount = pageStore.perLoadAllowedRequestCount; r.netFilteringSwitch = pageStore.getNetFilteringSwitch(); - r.hostnameDict = getHostnameDict(pageStore.hostnameToCountMap); + getHostnameDict(pageStore.hostnameToCountMap, r); r.contentLastModified = pageStore.contentLastModified; r.firewallRules = getFirewallRules(rootHostname, r.hostnameDict); r.canElementPicker = µb.URI.isNetworkURI(r.rawURL); diff --git a/src/js/popup.js b/src/js/popup.js index b46d8b36e..41850128b 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -117,6 +117,11 @@ const cachePopupData = function(data) { return popupData; } popupData = data; + if ( Array.isArray(popupData.cnameSet) ) { + popupData.cnameSet = new Set(popupData.cnameSet); + } else if ( popupData.cnameSet === undefined ) { + popupData.cnameSet = new Set(); + } scopeToSrcHostnameMap['.'] = popupData.pageHostname || ''; const hostnameDict = popupData.hostnameDict; if ( typeof hostnameDict !== 'object' ) { @@ -334,6 +339,7 @@ const buildAllFirewallRows = function() { classList.toggle('isRootContext', des === popupData.pageHostname); classList.toggle('isDomain', isDomain); classList.toggle('isSubDomain', !isDomain); + classList.toggle('isCname', popupData.cnameSet.has(des)); classList.toggle('allowed', hnDetails.allowCount !== 0); classList.toggle('blocked', hnDetails.blockCount !== 0); classList.toggle('totalAllowed', hnDetails.totalAllowCount !== 0); diff --git a/src/js/traffic.js b/src/js/traffic.js index 8410c9cf2..f2710ced8 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -103,8 +103,10 @@ const onBeforeRequest = function(details) { ) { pageStore.setFrame(details.frameId, details.url); } - if ( result !== 2 ) { return; } - return { cancel: false }; + if ( result === 2 ) { + return { cancel: false }; + } + return; } // Blocked