I've had this issue for months now, but the concept is pretty straightforward: I want to block some Malicious Site™ from programmatically opening tabs or popup windows.
With the chrome.tabs
API, I can listen with onCreated
when a new tab is created, and I can easily check who (i.e. which tab) opened that particular tab accessing the openerTabId
property of the Tab
object passed to the callback function.
Now, I would like to do the exact same thing when a new window is created: I would like to know which tab opened the window (if any, because it could have been opened by the user too), check its URL to see if it is the Malicious Site™, and act accordingly (i.e. block the popup). I tried doing it in the exact same way: request the array of tabs in the new window and check their openerTabId
property, but unfortunately such property is not defined! I searched the documentation and Googled for hours, but sadly it looks like there's no simple way to check who opened a window.
Stated the above, the only way I was able to do something even remotely close to what I really want, is the following:
windowWatchlist
.document.referrer
, which should contain the URL of the site which opened the tab: if the referrer URL contains the address of the Malicious Site™ I want to block popups from, the window is then closed and removed from the windowWatchlist
.windowWatchlist
, it gets removed from it.Here's the code (which runs in my background.js
script):
// Called on chrome.windows.onCreated
function watchPopupWindow(window) {
windowWatchlist.push(window.id);
console.log('Added window #' + window.id + ' to watchlist.');
}
// Called on chrome.windows.onRemoved
function unwatchPopupWindow(windowID) {
var index = windowWatchlist.indexOf(windowID);
// If the windowID is in the watchlist:
if (index != -1) {
// Remove it:
windowWatchlist.splice(index, 1);
console.log('Removed window #' + windowID + ' from watchlist.');
}
}
// Called on chrome.tabs.onUpdated
function blockPopupWindow(tabID, info, tab) {
// If this tab is in a window which is in the watchlist:
if (windowWatchlist.indexOf(tab.windowId) != -1 && info.url && info.url != 'about:blank') {
// Check the referrer of this tab:
chrome.tabs.executeScript(tabID, {code: 'document.referrer;'}, function(ref) {
// If the referrer is the malicious site to block:
if (ref && ref[0] && ref[0].indexOf("http://MALICIOUS-SITE.XXX") != -1) {
// Close the popup window:
chrome.windows.remove(tab.windowId, function() {
console.log('Blocked popup window #' + tab.windowId + '.');
if (chrome.runtime.lastError)
console.error(chrome.runtime.lastError.message);
});;
}
});
}
}
var windowWatchlist = [];
chrome.windows.onCreated.addListener(watchPopupWindow, {windowTypes: ['popup']});
chrome.windows.onRemoved.addListener(unwatchPopupWindow, {windowTypes: ['popup']});
chrome.tabs.onUpdated.addListener(blockPopupWindow);
Now, you may be wondering: why do you need all this mess only to check a referrer? Couldn't you just check the tabs contained in the window when the window is opened and check their referrer directly inside the callback of chrome.window.onCreated
? That's a clever question, and the answer is simple: the problem is that I cannot check the referrer of the tabs right when they are created, because they almost always need some time to load, and the referrer isn't loaded until the page starts loading inside the tab. Therefore, I need to check when a tab is updated, see if its window is in my watchlist, and then check its referrer. This is why chrome.tabs.onUpdated
is needed, since it fires its listeners whenever a tab changes state (e.g. tab.status
changes from "loading"
to "complete"
).
The reason why I call this solution "clumsy" and the reason why it doesn't really work should be already clear to anyone with some experience of JavaScript and web developing: document.referrer
isn't reliable at all, and is very often undefined
or (in case of multiple redirects) not the right one. This makes my script fail about 90% of the times, because it is unable to determine whether the popup window was opened by the Malicious Site™ or not.
Moreover, the Malicious Site™ often opens popups with URL about:blank
or no URL at all, and only when they are loaded, injects data into them, making them basically impossible to detect, even with chrome.tabs.onUpdated
which doesn't fire any listener in this situation.
I could decide to block any popup with URL about:blank
or undefined
, and this is what I'm doing right now indeed, but is a pretty bad compromise, since that I end up closing popups opened by any site which uses this method, and not only the Malicious Site™ I want to block.
My question is simple, but I don't know about its solution: does anyone know any other more reliable method which could be used to detect which tab opened a new window? Nothing comes to my mind, maybe something could be possible using the chrome.webRequest
API? I don't really know. For months I've been accepting the fact that a simple solution just wasn't possible, and helplessly waited for an update or something, but I never actually thought about asking here, because the problem looked above the competence of an average Chrome Extension programmer, but hopefully I was wrong.
UPDATE: The solution to inject a script inside the site and replace the window.open
function with something else isn't viable: if an <iframe>
is loaded without a src
attribute, but with an already written DOM inside the srcdoc
attribute, Chrome will not execute a content script inside it, even if the call to chrome.tabs.executeScript
is made with allFrames: true
, and even if the content script is declared inside the extension's manifest.
Here is the code: var win = window. open('http://www.google.com', 'google','width=800,height=600,status=0,toolbar=0'); var timer = setInterval(function() { if(win. closed) { clearInterval(timer); alert('closed'); } }, 1000);
var newWindow = window. open("", null, "height=200,width=400,status=yes,toolbar=no,menubar=no,location=no"); newWindow. document. write("<select>"); newWindow.
I came across the same problem and found the webNavigation.onCreatedNavigationTarget
event that yields the source tab/frame id when a new window is opened.
Solution found from this post: Is it possible to determine a tab's opener within a Google Chrome extension?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With