1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-10-06 09:37:12 +02:00

Match static popup filter against local context

Related feedback:
- https://www.reddit.com/r/uBlockOrigin/comments/d6zbqv/

For static filter `popup` filter purpose, the URL of the
embedded frame from which the popup was launched will
be used in the matching algorithm.
This commit is contained in:
Raymond Hill 2019-09-23 08:25:23 -04:00
parent d15163d3bb
commit f204d24bf4
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
3 changed files with 87 additions and 47 deletions

View File

@ -260,10 +260,7 @@ vAPI.Tabs = class {
details.url = this.sanitizeURL(details.url); details.url = this.sanitizeURL(details.url);
this.onNavigation(details); this.onNavigation(details);
} }
this.onCreated( this.onCreated(details);
details.tabId,
details.sourceTabId
);
}); });
browser.webNavigation.onCommitted.addListener(details => { browser.webNavigation.onCommitted.addListener(details => {
@ -592,7 +589,7 @@ vAPI.Tabs = class {
onClosed(/* tabId, details */) { onClosed(/* tabId, details */) {
} }
onCreated(/* openedTabId, openerTabId */) { onCreated(/* details */) {
} }
onNavigation(/* details */) { onNavigation(/* details */) {
@ -655,7 +652,7 @@ if ( browser.windows instanceof Object ) {
// Ensure ImageData for toolbar icon is valid before use. // Ensure ImageData for toolbar icon is valid before use.
vAPI.setIcon = (( ) => { vAPI.setIcon = (( ) => {
const browserAction = browser.browserAction; const browserAction = webext.browserAction;
const titleTemplate = const titleTemplate =
browser.runtime.getManifest().browser_action.default_title + browser.runtime.getManifest().browser_action.default_title +
' ({badge})'; ' ({badge})';

View File

@ -32,7 +32,9 @@ const promisifyNoFail = function(thisArg, fnName, outFn = r => r) {
return function() { return function() {
return new Promise(resolve => { return new Promise(resolve => {
fn.call(thisArg, ...arguments, function() { fn.call(thisArg, ...arguments, function() {
void chrome.runtime.lastError; if ( chrome.runtime.lastError instanceof Object ) {
void chrome.runtime.lastError.message;
}
resolve(outFn(...arguments)); resolve(outFn(...arguments));
}); });
}); });
@ -55,6 +57,14 @@ const promisify = function(thisArg, fnName) {
}; };
const webext = { const webext = {
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/browserAction
browserAction: {
onClicked: chrome.browserAction.onClicked,
setBadgeBackgroundColor: promisifyNoFail(chrome.browserAction, 'setBadgeBackgroundColor'),
setBadgeText: promisifyNoFail(chrome.browserAction, 'setBadgeText'),
setIcon: promisifyNoFail(chrome.browserAction, 'setIcon'),
setTitle: promisifyNoFail(chrome.browserAction, 'setTitle'),
},
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/menus // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/menus
menus: { menus: {
create: function() { create: function() {
@ -89,6 +99,10 @@ const webext = {
remove: promisifyNoFail(chrome.tabs, 'remove'), remove: promisifyNoFail(chrome.tabs, 'remove'),
update: promisifyNoFail(chrome.tabs, 'update', tab => tab instanceof Object ? tab : null), update: promisifyNoFail(chrome.tabs, 'update', tab => tab instanceof Object ? tab : null),
}, },
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webNavigation
webNavigation: {
getFrame: promisify(chrome.webNavigation, 'getFrame'),
},
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/windows // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/windows
windows: { windows: {
get: promisifyNoFail(chrome.windows, 'get', win => win instanceof Object ? win : null), get: promisifyNoFail(chrome.windows, 'get', win => win instanceof Object ? win : null),

View File

@ -103,12 +103,13 @@
const popupMatch = function( const popupMatch = function(
fctxt, fctxt,
openerURL, rootOpenerURL,
localOpenerURL,
targetURL, targetURL,
popupType popupType = 'popup'
) { ) {
fctxt.setTabOriginFromURL(openerURL) fctxt.setTabOriginFromURL(rootOpenerURL)
.setDocOriginFromURL(openerURL) .setDocOriginFromURL(localOpenerURL || rootOpenerURL)
.setURL(targetURL) .setURL(targetURL)
.setType('popup'); .setType('popup');
let result; let result;
@ -231,10 +232,17 @@
const popunderMatch = function( const popunderMatch = function(
fctxt, fctxt,
openerURL, rootOpenerURL,
localOpenerURL,
targetURL targetURL
) { ) {
let result = popupMatch(fctxt, targetURL, openerURL, 'popunder'); let result = popupMatch(
fctxt,
targetURL,
undefined,
rootOpenerURL,
'popunder'
);
if ( result === 1 ) { return result; } if ( result === 1 ) { return result; }
// https://github.com/gorhill/uBlock/issues/1010#issuecomment-186824878 // https://github.com/gorhill/uBlock/issues/1010#issuecomment-186824878
@ -243,7 +251,7 @@
// a broad one, we will consider the opener tab to be a popunder tab. // a broad one, we will consider the opener tab to be a popunder tab.
// For now, a "broad" filter is one which does not touch any part of // For now, a "broad" filter is one which does not touch any part of
// the hostname part of the opener URL. // the hostname part of the opener URL.
let popunderURL = openerURL, let popunderURL = rootOpenerURL,
popunderHostname = µb.URI.hostnameFromURI(popunderURL); popunderHostname = µb.URI.hostnameFromURI(popunderURL);
if ( popunderHostname === '' ) { return 0; } if ( popunderHostname === '' ) { return 0; }
@ -251,7 +259,7 @@
fctxt, fctxt,
popunderURL, popunderURL,
popunderHostname, popunderHostname,
popupMatch(fctxt, targetURL, popunderURL, 'popup') popupMatch(fctxt, targetURL, undefined, popunderURL)
); );
if ( result !== 0 ) { return result; } if ( result !== 0 ) { return result; }
@ -264,7 +272,7 @@
fctxt, fctxt,
popunderURL, popunderURL,
popunderHostname, popunderHostname,
popupMatch(fctxt, targetURL, popunderURL, 'popup') popupMatch(fctxt, targetURL, undefined, popunderURL)
); );
}; };
@ -273,8 +281,11 @@
const openerTabId = openerDetails.tabId; const openerTabId = openerDetails.tabId;
let tabContext = µb.tabContextManager.lookup(openerTabId); let tabContext = µb.tabContextManager.lookup(openerTabId);
if ( tabContext === null ) { return; } if ( tabContext === null ) { return; }
const openerURL = tabContext.rawURL; const rootOpenerURL = tabContext.rawURL;
if ( openerURL === '' ) { return; } if ( rootOpenerURL === '' ) { return; }
const localOpenerURL = openerDetails.frameId !== 0
? openerDetails.frameURL
: undefined;
// Popup details. // Popup details.
tabContext = µb.tabContextManager.lookup(targetTabId); tabContext = µb.tabContextManager.lookup(targetTabId);
@ -283,21 +294,20 @@
if ( targetURL === '' ) { return; } if ( targetURL === '' ) { return; }
// https://github.com/gorhill/uBlock/issues/341 // https://github.com/gorhill/uBlock/issues/341
// Allow popups if uBlock is turned off in opener's context. // Allow popups if uBlock is turned off in opener's context.
if ( µb.getNetFilteringSwitch(openerURL) === false ) { return; } if ( µb.getNetFilteringSwitch(rootOpenerURL) === false ) { return; }
// https://github.com/gorhill/uBlock/issues/1538 // https://github.com/gorhill/uBlock/issues/1538
if ( if (
µb.getNetFilteringSwitch(µb.normalizePageURL( µb.getNetFilteringSwitch(
openerTabId, µb.normalizePageURL(openerTabId, rootOpenerURL)
openerURL)
) === false ) === false
) { ) {
return; return;
} }
// If the page URL is that of our "blocked page" URL, extract the URL of // If the page URL is that of our "blocked page" URL, extract the URL
// the page which was blocked. // of the page which was blocked.
if ( targetURL.startsWith(vAPI.getURL('document-blocked.html')) ) { if ( targetURL.startsWith(vAPI.getURL('document-blocked.html')) ) {
const matches = /details=([^&]+)/.exec(targetURL); const matches = /details=([^&]+)/.exec(targetURL);
if ( matches !== null ) { if ( matches !== null ) {
@ -314,12 +324,12 @@
// https://github.com/gorhill/uBlock/issues/2919 // https://github.com/gorhill/uBlock/issues/2919
// - If the target tab matches a clicked link, assume it's legit. // - If the target tab matches a clicked link, assume it's legit.
if ( areDifferentURLs(targetURL, openerDetails.trustedURL) ) { if ( areDifferentURLs(targetURL, openerDetails.trustedURL) ) {
result = popupMatch(fctxt, openerURL, targetURL, 'popup'); result = popupMatch(fctxt, rootOpenerURL, localOpenerURL, targetURL);
} }
// Popunder test. // Popunder test.
if ( result === 0 && openerDetails.popunder ) { if ( result === 0 && openerDetails.popunder ) {
result = popunderMatch(fctxt, openerURL, targetURL); result = popunderMatch(fctxt, rootOpenerURL, localOpenerURL, targetURL);
if ( result === 1 ) { if ( result === 1 ) {
popupType = 'popunder'; popupType = 'popunder';
} }
@ -332,10 +342,10 @@
if ( popupType === 'popup' ) { if ( popupType === 'popup' ) {
fctxt.setURL(targetURL) fctxt.setURL(targetURL)
.setTabId(openerTabId) .setTabId(openerTabId)
.setTabOriginFromURL(openerURL) .setTabOriginFromURL(rootOpenerURL)
.setDocOriginFromURL(openerURL); .setDocOriginFromURL(localOpenerURL);
} else { } else {
fctxt.setURL(openerURL) fctxt.setURL(rootOpenerURL)
.setTabId(targetTabId) .setTabId(targetTabId)
.setTabOriginFromURL(targetURL) .setTabOriginFromURL(targetURL)
.setDocOriginFromURL(targetURL); .setDocOriginFromURL(targetURL);
@ -446,12 +456,15 @@ housekeep itself.
const popupCandidates = new Map(); const popupCandidates = new Map();
const PopupCandidate = class { const PopupCandidate = class {
constructor(targetTabId, openerTabId) { constructor(createDetails, openerDetails) {
this.targetTabId = targetTabId; this.targetTabId = createDetails.tabId;
this.opener = { this.opener = {
tabId: openerTabId, tabId: createDetails.sourceTabId,
tabURL: openerDetails[0].url,
frameId: createDetails.sourceFrameId,
frameURL: openerDetails[1].url,
popunder: false, popunder: false,
trustedURL: openerTabId === µb.maybeGoodPopup.tabId trustedURL: createDetails.tabId === µb.maybeGoodPopup.tabId
? µb.maybeGoodPopup.url ? µb.maybeGoodPopup.url
: '' : ''
}; };
@ -477,10 +490,8 @@ housekeep itself.
} }
}; };
const popupCandidateTest = function(targetTabId) { const popupCandidateTest = async function(targetTabId) {
for ( const entry of popupCandidates ) { for ( const [ tabId, candidate ] of popupCandidates ) {
const tabId = entry[0];
const candidate = entry[1];
if ( if (
targetTabId !== tabId && targetTabId !== tabId &&
targetTabId !== candidate.opener.tabId targetTabId !== candidate.opener.tabId
@ -493,7 +504,8 @@ housekeep itself.
if ( targetTabId === candidate.opener.tabId ) { if ( targetTabId === candidate.opener.tabId ) {
candidate.opener.popunder = true; candidate.opener.popunder = true;
} }
if ( µb.onPopupUpdated(tabId, candidate.opener) === true ) { const result = await µb.onPopupUpdated(tabId, candidate.opener);
if ( result === true ) {
candidate.destroy(); candidate.destroy();
} else { } else {
candidate.launchSelfDestruction(); candidate.launchSelfDestruction();
@ -501,15 +513,32 @@ housekeep itself.
} }
}; };
const onTabCreated = function(targetTabId, openerTabId) { const onTabCreated = async function(createDetails) {
const popup = popupCandidates.get(targetTabId); const { sourceTabId, sourceFrameId, tabId } = createDetails;
const popup = popupCandidates.get(tabId);
if ( popup === undefined ) { if ( popup === undefined ) {
let openerDetails;
try {
openerDetails = await Promise.all([
webext.webNavigation.getFrame({
tabId: createDetails.sourceTabId,
frameId: 0,
}),
webext.webNavigation.getFrame({
tabId: sourceTabId,
frameId: sourceFrameId,
}),
]);
}
catch (reason) {
return;
}
popupCandidates.set( popupCandidates.set(
targetTabId, tabId,
new PopupCandidate(targetTabId, openerTabId) new PopupCandidate(createDetails, openerDetails)
); );
} }
popupCandidateTest(targetTabId); popupCandidateTest(tabId);
}; };
const gcPeriod = 10 * 60 * 1000; const gcPeriod = 10 * 60 * 1000;
@ -818,9 +847,9 @@ vAPI.Tabs = class extends vAPI.Tabs {
µBlock.contextMenu.update(); µBlock.contextMenu.update();
} }
onCreated(targetTabId, openerTabId) { onCreated(details) {
super.onCreated(targetTabId, openerTabId); super.onCreated(details);
µBlock.tabContextManager.onTabCreated(targetTabId, openerTabId); µBlock.tabContextManager.onTabCreated(details);
} }
// When the DOM content of root frame is loaded, this means the tab // When the DOM content of root frame is loaded, this means the tab