mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-10 09:07:54 +01: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:
parent
d15163d3bb
commit
f204d24bf4
3 changed files with 87 additions and 47 deletions
|
@ -260,10 +260,7 @@ vAPI.Tabs = class {
|
|||
details.url = this.sanitizeURL(details.url);
|
||||
this.onNavigation(details);
|
||||
}
|
||||
this.onCreated(
|
||||
details.tabId,
|
||||
details.sourceTabId
|
||||
);
|
||||
this.onCreated(details);
|
||||
});
|
||||
|
||||
browser.webNavigation.onCommitted.addListener(details => {
|
||||
|
@ -592,7 +589,7 @@ vAPI.Tabs = class {
|
|||
onClosed(/* tabId, details */) {
|
||||
}
|
||||
|
||||
onCreated(/* openedTabId, openerTabId */) {
|
||||
onCreated(/* details */) {
|
||||
}
|
||||
|
||||
onNavigation(/* details */) {
|
||||
|
@ -655,7 +652,7 @@ if ( browser.windows instanceof Object ) {
|
|||
// Ensure ImageData for toolbar icon is valid before use.
|
||||
|
||||
vAPI.setIcon = (( ) => {
|
||||
const browserAction = browser.browserAction;
|
||||
const browserAction = webext.browserAction;
|
||||
const titleTemplate =
|
||||
browser.runtime.getManifest().browser_action.default_title +
|
||||
' ({badge})';
|
||||
|
|
|
@ -32,7 +32,9 @@ const promisifyNoFail = function(thisArg, fnName, outFn = r => r) {
|
|||
return function() {
|
||||
return new Promise(resolve => {
|
||||
fn.call(thisArg, ...arguments, function() {
|
||||
void chrome.runtime.lastError;
|
||||
if ( chrome.runtime.lastError instanceof Object ) {
|
||||
void chrome.runtime.lastError.message;
|
||||
}
|
||||
resolve(outFn(...arguments));
|
||||
});
|
||||
});
|
||||
|
@ -55,6 +57,14 @@ const promisify = function(thisArg, fnName) {
|
|||
};
|
||||
|
||||
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
|
||||
menus: {
|
||||
create: function() {
|
||||
|
@ -89,6 +99,10 @@ const webext = {
|
|||
remove: promisifyNoFail(chrome.tabs, 'remove'),
|
||||
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
|
||||
windows: {
|
||||
get: promisifyNoFail(chrome.windows, 'get', win => win instanceof Object ? win : null),
|
||||
|
|
109
src/js/tab.js
109
src/js/tab.js
|
@ -103,12 +103,13 @@
|
|||
|
||||
const popupMatch = function(
|
||||
fctxt,
|
||||
openerURL,
|
||||
rootOpenerURL,
|
||||
localOpenerURL,
|
||||
targetURL,
|
||||
popupType
|
||||
popupType = 'popup'
|
||||
) {
|
||||
fctxt.setTabOriginFromURL(openerURL)
|
||||
.setDocOriginFromURL(openerURL)
|
||||
fctxt.setTabOriginFromURL(rootOpenerURL)
|
||||
.setDocOriginFromURL(localOpenerURL || rootOpenerURL)
|
||||
.setURL(targetURL)
|
||||
.setType('popup');
|
||||
let result;
|
||||
|
@ -231,10 +232,17 @@
|
|||
|
||||
const popunderMatch = function(
|
||||
fctxt,
|
||||
openerURL,
|
||||
rootOpenerURL,
|
||||
localOpenerURL,
|
||||
targetURL
|
||||
) {
|
||||
let result = popupMatch(fctxt, targetURL, openerURL, 'popunder');
|
||||
let result = popupMatch(
|
||||
fctxt,
|
||||
targetURL,
|
||||
undefined,
|
||||
rootOpenerURL,
|
||||
'popunder'
|
||||
);
|
||||
if ( result === 1 ) { return result; }
|
||||
|
||||
// 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.
|
||||
// For now, a "broad" filter is one which does not touch any part of
|
||||
// the hostname part of the opener URL.
|
||||
let popunderURL = openerURL,
|
||||
let popunderURL = rootOpenerURL,
|
||||
popunderHostname = µb.URI.hostnameFromURI(popunderURL);
|
||||
if ( popunderHostname === '' ) { return 0; }
|
||||
|
||||
|
@ -251,7 +259,7 @@
|
|||
fctxt,
|
||||
popunderURL,
|
||||
popunderHostname,
|
||||
popupMatch(fctxt, targetURL, popunderURL, 'popup')
|
||||
popupMatch(fctxt, targetURL, undefined, popunderURL)
|
||||
);
|
||||
if ( result !== 0 ) { return result; }
|
||||
|
||||
|
@ -264,7 +272,7 @@
|
|||
fctxt,
|
||||
popunderURL,
|
||||
popunderHostname,
|
||||
popupMatch(fctxt, targetURL, popunderURL, 'popup')
|
||||
popupMatch(fctxt, targetURL, undefined, popunderURL)
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -273,8 +281,11 @@
|
|||
const openerTabId = openerDetails.tabId;
|
||||
let tabContext = µb.tabContextManager.lookup(openerTabId);
|
||||
if ( tabContext === null ) { return; }
|
||||
const openerURL = tabContext.rawURL;
|
||||
if ( openerURL === '' ) { return; }
|
||||
const rootOpenerURL = tabContext.rawURL;
|
||||
if ( rootOpenerURL === '' ) { return; }
|
||||
const localOpenerURL = openerDetails.frameId !== 0
|
||||
? openerDetails.frameURL
|
||||
: undefined;
|
||||
|
||||
// Popup details.
|
||||
tabContext = µb.tabContextManager.lookup(targetTabId);
|
||||
|
@ -283,21 +294,20 @@
|
|||
if ( targetURL === '' ) { return; }
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/341
|
||||
// Allow popups if uBlock is turned off in opener's context.
|
||||
if ( µb.getNetFilteringSwitch(openerURL) === false ) { return; }
|
||||
// Allow popups if uBlock is turned off in opener's context.
|
||||
if ( µb.getNetFilteringSwitch(rootOpenerURL) === false ) { return; }
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/1538
|
||||
if (
|
||||
µb.getNetFilteringSwitch(µb.normalizePageURL(
|
||||
openerTabId,
|
||||
openerURL)
|
||||
µb.getNetFilteringSwitch(
|
||||
µb.normalizePageURL(openerTabId, rootOpenerURL)
|
||||
) === false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the page URL is that of our "blocked page" URL, extract the URL of
|
||||
// the page which was blocked.
|
||||
// If the page URL is that of our "blocked page" URL, extract the URL
|
||||
// of the page which was blocked.
|
||||
if ( targetURL.startsWith(vAPI.getURL('document-blocked.html')) ) {
|
||||
const matches = /details=([^&]+)/.exec(targetURL);
|
||||
if ( matches !== null ) {
|
||||
|
@ -314,12 +324,12 @@
|
|||
// https://github.com/gorhill/uBlock/issues/2919
|
||||
// - If the target tab matches a clicked link, assume it's legit.
|
||||
if ( areDifferentURLs(targetURL, openerDetails.trustedURL) ) {
|
||||
result = popupMatch(fctxt, openerURL, targetURL, 'popup');
|
||||
result = popupMatch(fctxt, rootOpenerURL, localOpenerURL, targetURL);
|
||||
}
|
||||
|
||||
// Popunder test.
|
||||
if ( result === 0 && openerDetails.popunder ) {
|
||||
result = popunderMatch(fctxt, openerURL, targetURL);
|
||||
result = popunderMatch(fctxt, rootOpenerURL, localOpenerURL, targetURL);
|
||||
if ( result === 1 ) {
|
||||
popupType = 'popunder';
|
||||
}
|
||||
|
@ -332,10 +342,10 @@
|
|||
if ( popupType === 'popup' ) {
|
||||
fctxt.setURL(targetURL)
|
||||
.setTabId(openerTabId)
|
||||
.setTabOriginFromURL(openerURL)
|
||||
.setDocOriginFromURL(openerURL);
|
||||
.setTabOriginFromURL(rootOpenerURL)
|
||||
.setDocOriginFromURL(localOpenerURL);
|
||||
} else {
|
||||
fctxt.setURL(openerURL)
|
||||
fctxt.setURL(rootOpenerURL)
|
||||
.setTabId(targetTabId)
|
||||
.setTabOriginFromURL(targetURL)
|
||||
.setDocOriginFromURL(targetURL);
|
||||
|
@ -446,12 +456,15 @@ housekeep itself.
|
|||
const popupCandidates = new Map();
|
||||
|
||||
const PopupCandidate = class {
|
||||
constructor(targetTabId, openerTabId) {
|
||||
this.targetTabId = targetTabId;
|
||||
constructor(createDetails, openerDetails) {
|
||||
this.targetTabId = createDetails.tabId;
|
||||
this.opener = {
|
||||
tabId: openerTabId,
|
||||
tabId: createDetails.sourceTabId,
|
||||
tabURL: openerDetails[0].url,
|
||||
frameId: createDetails.sourceFrameId,
|
||||
frameURL: openerDetails[1].url,
|
||||
popunder: false,
|
||||
trustedURL: openerTabId === µb.maybeGoodPopup.tabId
|
||||
trustedURL: createDetails.tabId === µb.maybeGoodPopup.tabId
|
||||
? µb.maybeGoodPopup.url
|
||||
: ''
|
||||
};
|
||||
|
@ -477,10 +490,8 @@ housekeep itself.
|
|||
}
|
||||
};
|
||||
|
||||
const popupCandidateTest = function(targetTabId) {
|
||||
for ( const entry of popupCandidates ) {
|
||||
const tabId = entry[0];
|
||||
const candidate = entry[1];
|
||||
const popupCandidateTest = async function(targetTabId) {
|
||||
for ( const [ tabId, candidate ] of popupCandidates ) {
|
||||
if (
|
||||
targetTabId !== tabId &&
|
||||
targetTabId !== candidate.opener.tabId
|
||||
|
@ -493,7 +504,8 @@ housekeep itself.
|
|||
if ( targetTabId === candidate.opener.tabId ) {
|
||||
candidate.opener.popunder = true;
|
||||
}
|
||||
if ( µb.onPopupUpdated(tabId, candidate.opener) === true ) {
|
||||
const result = await µb.onPopupUpdated(tabId, candidate.opener);
|
||||
if ( result === true ) {
|
||||
candidate.destroy();
|
||||
} else {
|
||||
candidate.launchSelfDestruction();
|
||||
|
@ -501,15 +513,32 @@ housekeep itself.
|
|||
}
|
||||
};
|
||||
|
||||
const onTabCreated = function(targetTabId, openerTabId) {
|
||||
const popup = popupCandidates.get(targetTabId);
|
||||
const onTabCreated = async function(createDetails) {
|
||||
const { sourceTabId, sourceFrameId, tabId } = createDetails;
|
||||
const popup = popupCandidates.get(tabId);
|
||||
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(
|
||||
targetTabId,
|
||||
new PopupCandidate(targetTabId, openerTabId)
|
||||
tabId,
|
||||
new PopupCandidate(createDetails, openerDetails)
|
||||
);
|
||||
}
|
||||
popupCandidateTest(targetTabId);
|
||||
popupCandidateTest(tabId);
|
||||
};
|
||||
|
||||
const gcPeriod = 10 * 60 * 1000;
|
||||
|
@ -818,9 +847,9 @@ vAPI.Tabs = class extends vAPI.Tabs {
|
|||
µBlock.contextMenu.update();
|
||||
}
|
||||
|
||||
onCreated(targetTabId, openerTabId) {
|
||||
super.onCreated(targetTabId, openerTabId);
|
||||
µBlock.tabContextManager.onTabCreated(targetTabId, openerTabId);
|
||||
onCreated(details) {
|
||||
super.onCreated(details);
|
||||
µBlock.tabContextManager.onTabCreated(details);
|
||||
}
|
||||
|
||||
// When the DOM content of root frame is loaded, this means the tab
|
||||
|
|
Loading…
Reference in a new issue