Browse Source

Implement pop-up blocking for Safari

It works similarly to the xhr intercepting, except here the window.open
global function is being overridden.
Note that it could only work if the site's Content Security Policy allows
inline scripts, and the script on the webpage doesn't have a copy of the
original window.open function (it can happen only if the page has an
inline script in its head element, where the reference to the original
function can be obtained - likely this cannot be prevented in Safari).
pull/2/head
Deathamns 10 years ago
committed by gorhill
parent
commit
31f9683d9f
  1. 74
      src/js/vapi-background.js

74
src/js/vapi-background.js

@ -1,3 +1,4 @@
/* global SafariBrowserTab, Services, XPCOMUtils */
// for background page only // for background page only
(function() { (function() {
@ -392,16 +393,11 @@ if (window.chrome) {
} }
// ?? // ??
/*if (typeof onUpdated === 'function') {
chrome.tabs.onUpdated.addListener(this.onUpdated);
}*/
/* if (typeof this.onUpdated === 'function') { } */
// onClosed handled in the main tab-close event // onClosed handled in the main tab-close event
// maybe intercept window.open on web-pages?
/*if (typeof onPopup === 'function') {
chrome.webNavigation.onCreatedNavigationTarget.addListener(this.onPopup);
}*/
// onPopup is handled in window.open on web-pages?
/* if (typeof onPopup === 'function') { } */
}, },
getTabId: function(tab) { getTabId: function(tab) {
for (var i in vAPI.tabs.stack) { for (var i in vAPI.tabs.stack) {
@ -653,10 +649,6 @@ if (window.chrome) {
} }
this.connector = function(request) { this.connector = function(request) {
if (request.name === 'canLoad') {
return;
}
var callback = function(response) { var callback = function(response) {
if (request.message.requestId && response !== undefined) { if (request.message.requestId && response !== undefined) {
request.target.page.dispatchMessage( request.target.page.dispatchMessage(
@ -689,6 +681,9 @@ if (window.chrome) {
} }
}; };
// the third parameter must stay false (bubbling), so later
// onBeforeRequest will use true (capturing), where we can invoke
// stopPropagation() (this way this.connector won't be fired)
safari.application.addEventListener('message', this.connector, false); safari.application.addEventListener('message', this.connector, false);
}, },
broadcast: function(message) { broadcast: function(message) {
@ -705,8 +700,6 @@ if (window.chrome) {
vAPI.net = { vAPI.net = {
registerListeners: function() { registerListeners: function() {
// onBeforeRequest is used in the messaging above, in the connector method
// in order to use only one listener
var onBeforeRequest = this.onBeforeRequest; var onBeforeRequest = this.onBeforeRequest;
if (typeof onBeforeRequest.callback === 'function') { if (typeof onBeforeRequest.callback === 'function') {
@ -715,53 +708,67 @@ if (window.chrome) {
} }
onBeforeRequest = onBeforeRequest.callback; onBeforeRequest = onBeforeRequest.callback;
this.onBeforeRequest.callback = function(request) {
if (request.name !== 'canLoad') {
this.onBeforeRequest.callback = function(e) {
if (e.name !== 'canLoad') {
return; return;
} }
// no stopPropagation if it was called from beforeNavigate event // no stopPropagation if it was called from beforeNavigate event
if (request.stopPropagation) {
request.stopPropagation();
if (e.stopPropagation) {
e.stopPropagation();
} }
var block = vAPI.net.onBeforeRequest;
// blocking unwanted pop-ups
if (e.message.type === 'popup') {
if (typeof vAPI.tabs.onPopup === 'function') {
e.message.type = 'main_frame';
e.message.sourceTabId = vAPI.tabs.getTabId(e.target);
if (block.types.indexOf(request.message.type) < 0) {
if (vAPI.tabs.onPopup(e.message)) {
e.message = false;
return; return;
} }
}
request.message.tabId = vAPI.tabs.getTabId(request.target);
block = onBeforeRequest(request.message);
e.message = true;
return;
}
var block = vAPI.net.onBeforeRequest;
if (block.types.indexOf(e.message.type) < 0) {
return true;
}
e.message.tabId = vAPI.tabs.getTabId(e.target);
block = onBeforeRequest(e.message);
// truthy return value will allow the request, // truthy return value will allow the request,
// except when redirectUrl is present // except when redirectUrl is present
if (block && typeof block === 'object') { if (block && typeof block === 'object') {
if (block.cancel) { if (block.cancel) {
request.message = false;
e.message = false;
} }
else if (typeof block.redirectUrl === "string") {
request.message = block.redirectUrl;
else if (e.message.type === 'script'
&& typeof block.redirectUrl === "string") {
e.message = block.redirectUrl;
} }
else { else {
request.message = true;
e.message = true;
} }
} }
else { else {
request.message = true;
e.message = true;
} }
return request.message;
return e.message;
}; };
safari.application.addEventListener('message', this.onBeforeRequest.callback, true); safari.application.addEventListener('message', this.onBeforeRequest.callback, true);
// 'main_frame' simulation, since this isn't available in beforeload // 'main_frame' simulation, since this isn't available in beforeload
safari.application.addEventListener('beforeNavigate', function(e) { safari.application.addEventListener('beforeNavigate', function(e) {
// e.url is not present for local files or data URIs // e.url is not present for local files or data URIs
if (!e.url) {
return;
}
if (e.url) {
vAPI.net.onBeforeRequest.callback({ vAPI.net.onBeforeRequest.callback({
name: 'canLoad', name: 'canLoad',
target: e.target, target: e.target,
@ -773,6 +780,7 @@ if (window.chrome) {
timeStamp: e.timeStamp timeStamp: e.timeStamp
} }
}) || e.preventDefault(); }) || e.preventDefault();
}
}, true); }, true);
} }
} }
@ -861,7 +869,7 @@ if (window.chrome) {
safari.application.addEventListener('contextmenu', this.onContextMenu); safari.application.addEventListener('contextmenu', this.onContextMenu);
safari.application.addEventListener("command", this.onContextMenuCommand); safari.application.addEventListener("command", this.onContextMenuCommand);
}, },
remove: function(argument) {
remove: function() {
safari.application.removeEventListener('contextmenu', this.onContextMenu); safari.application.removeEventListener('contextmenu', this.onContextMenu);
safari.application.removeEventListener("command", this.onContextMenuCommand); safari.application.removeEventListener("command", this.onContextMenuCommand);
this.onContextMenu = null; this.onContextMenu = null;

Loading…
Cancel
Save