1
0
Fork 0
mirror of https://github.com/gorhill/uMatrix.git synced 2024-06-18 02:05:06 +12:00
uMatrix/src/js/contentscript-end.js

303 lines
9.9 KiB
JavaScript
Raw Normal View History

2014-10-18 08:01:09 +13:00
/*******************************************************************************
µMatrix - a Chromium browser extension to black/white list requests.
Copyright (C) 2014 Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uMatrix
*/
2015-04-12 09:15:57 +12:00
/* global vAPI */
/* jshint multistr: true, boss: true */
2014-10-18 08:01:09 +13:00
/******************************************************************************/
/******************************************************************************/
2015-04-12 09:15:57 +12:00
// Injected into content pages
2014-10-18 08:01:09 +13:00
2015-04-12 09:15:57 +12:00
(function() {
2014-10-18 08:01:09 +13:00
2015-04-12 09:15:57 +12:00
'use strict';
2014-10-18 08:01:09 +13:00
2015-04-12 09:15:57 +12:00
/******************************************************************************/
2014-10-18 08:01:09 +13:00
2015-04-12 09:15:57 +12:00
// https://github.com/chrisaljoudi/uBlock/issues/464
if ( document instanceof HTMLDocument === false ) {
//console.debug('contentscript-end.js > not a HTLMDocument');
return false;
}
2014-10-18 08:01:09 +13:00
2015-04-12 09:15:57 +12:00
// This can happen
if ( !vAPI ) {
//console.debug('contentscript-end.js > vAPI not found');
return;
}
2014-10-18 08:01:09 +13:00
2015-04-12 09:15:57 +12:00
// https://github.com/chrisaljoudi/uBlock/issues/587
// Pointless to execute without the start script having done its job.
if ( !vAPI.contentscriptStartInjected ) {
return;
}
2014-10-18 08:01:09 +13:00
2015-04-12 09:15:57 +12:00
// https://github.com/chrisaljoudi/uBlock/issues/456
// Already injected?
if ( vAPI.contentscriptEndInjected ) {
//console.debug('contentscript-end.js > content script already injected');
return;
}
vAPI.contentscriptEndInjected = true;
2014-10-18 08:01:09 +13:00
2015-04-12 09:15:57 +12:00
/******************************************************************************/
2014-10-18 08:01:09 +13:00
2015-04-12 09:15:57 +12:00
var localMessager = vAPI.messaging.channel('contentscript-end.js');
2014-10-18 08:01:09 +13:00
/******************************************************************************/
/******************************************************************************/
// This is to be executed only once: putting this code in its own closure
// means the code will be flushed from memory once executed.
(function() {
/******************************************************************************/
/*------------[ Unrendered Noscript (because CSP) Workaround ]----------------*/
var checkScriptBlacklistedHandler = function(response) {
if ( !response.scriptBlacklisted ) {
return;
}
var scripts = document.querySelectorAll('noscript');
var i = scripts.length;
var realNoscript, fakeNoscript;
while ( i-- ) {
realNoscript = scripts[i];
fakeNoscript = document.createElement('div');
fakeNoscript.innerHTML = '<!-- uMatrix NOSCRIPT tag replacement: see <https://github.com/gorhill/httpswitchboard/issues/177> -->\n' + realNoscript.textContent;
realNoscript.parentNode.replaceChild(fakeNoscript, realNoscript);
}
};
2015-04-12 09:15:57 +12:00
localMessager.send({
2014-10-18 08:01:09 +13:00
what: 'checkScriptBlacklisted',
url: window.location.href
2015-04-12 09:15:57 +12:00
}, checkScriptBlacklistedHandler);
2014-10-18 08:01:09 +13:00
/******************************************************************************/
var localStorageHandler = function(mustRemove) {
if ( mustRemove ) {
window.localStorage.clear();
2014-10-27 12:41:22 +13:00
window.sessionStorage.clear();
2014-10-18 08:01:09 +13:00
// console.debug('HTTP Switchboard > found and removed non-empty localStorage');
}
};
// Check with extension whether local storage must be emptied
// rhill 2014-03-28: we need an exception handler in case 3rd-party access
// to site data is disabled.
// https://github.com/gorhill/httpswitchboard/issues/215
try {
2014-10-27 12:41:22 +13:00
var hasLocalStorage = window.localStorage && window.localStorage.length;
var hasSessionStorage = window.sessionStorage && window.sessionStorage.length;
if ( hasLocalStorage || hasSessionStorage ) {
2015-04-12 09:15:57 +12:00
localMessager.send({
2014-10-18 08:01:09 +13:00
what: 'contentScriptHasLocalStorage',
url: window.location.href
2015-04-12 09:15:57 +12:00
}, localStorageHandler);
2014-10-18 08:01:09 +13:00
}
// TODO: indexedDB
if ( window.indexedDB && !!window.indexedDB.webkitGetDatabaseNames ) {
// var db = window.indexedDB.webkitGetDatabaseNames().onsuccess = function(sender) {
// console.debug('webkitGetDatabaseNames(): result=%o', sender.target.result);
// };
}
// TODO: Web SQL
if ( window.openDatabase ) {
// Sad:
// "There is no way to enumerate or delete the databases available for an origin from this API."
// Ref.: http://www.w3.org/TR/webdatabase/#databases
}
}
catch (e) {
}
/******************************************************************************/
})();
/******************************************************************************/
/******************************************************************************/
(function() {
/******************************************************************************/
var nodesAddedHandler = function(nodeList, summary) {
var i = 0;
var node, src, text;
while ( node = nodeList.item(i++) ) {
if ( node.nodeType !== 1 ) {
continue;
}
if ( typeof node.tagName !== 'string' ) {
2014-10-18 08:01:09 +13:00
continue;
}
switch ( node.tagName.toUpperCase() ) {
case 'SCRIPT':
// https://github.com/gorhill/httpswitchboard/issues/252
// Do not count µMatrix's own script tags, they are not required
// to "unbreak" a web page
if ( node.id && node.id.indexOf('uMatrix-') === 0 ) {
break;
}
text = node.textContent.trim();
if ( text !== '' ) {
summary.scriptSources['{inline_script}'] = true;
summary.mustReport = true;
}
src = (node.src || '').trim();
if ( src !== '' ) {
summary.scriptSources[src] = true;
summary.mustReport = true;
}
break;
case 'A':
if ( node.href.indexOf('javascript:') === 0 ) {
summary.scriptSources['{inline_script}'] = true;
summary.mustReport = true;
}
break;
case 'OBJECT':
src = (node.data || '').trim();
if ( src !== '' ) {
summary.pluginSources[src] = true;
summary.mustReport = true;
}
break;
case 'EMBED':
src = (node.src || '').trim();
if ( src !== '' ) {
summary.pluginSources[src] = true;
summary.mustReport = true;
}
break;
}
}
};
/******************************************************************************/
var nodeListsAddedHandler = function(nodeLists) {
var i = nodeLists.length;
if ( i === 0 ) {
return;
}
2014-10-18 08:01:09 +13:00
var summary = {
what: 'contentScriptSummary',
locationURL: window.location.href,
scriptSources: {}, // to avoid duplicates
pluginSources: {}, // to avoid duplicates
mustReport: false
};
while ( i-- ) {
nodesAddedHandler(nodeLists[i], summary);
}
if ( summary.mustReport ) {
2015-04-12 09:15:57 +12:00
localMessager.send(summary);
2014-10-18 08:01:09 +13:00
}
};
/******************************************************************************/
(function() {
var summary = {
what: 'contentScriptSummary',
locationURL: window.location.href,
scriptSources: {}, // to avoid duplicates
pluginSources: {}, // to avoid duplicates
mustReport: true
};
// https://github.com/gorhill/httpswitchboard/issues/25
// &
// Looks for inline javascript also in at least one a[href] element.
// https://github.com/gorhill/httpswitchboard/issues/131
nodesAddedHandler(document.querySelectorAll('script, a[href^="javascript:"], object, embed'), summary);
//console.debug('contentscript-end.js > firstObservationHandler(): found %d script tags in "%s"', Object.keys(summary.scriptSources).length, window.location.href);
2015-04-12 09:15:57 +12:00
localMessager.send(summary);
2014-10-18 08:01:09 +13:00
})();
/******************************************************************************/
// Observe changes in the DOM
// Added node lists will be cumulated here before being processed
var addedNodeLists = [];
var addedNodeListsTimer = null;
var treeMutationObservedHandler = function() {
nodeListsAddedHandler(addedNodeLists);
addedNodeListsTimer = null;
addedNodeLists = [];
};
// https://github.com/gorhill/uBlock/issues/205
// Do not handle added node directly from within mutation observer.
var treeMutationObservedHandlerAsync = function(mutations) {
var iMutation = mutations.length;
var nodeList;
while ( iMutation-- ) {
nodeList = mutations[iMutation].addedNodes;
if ( nodeList.length !== 0 ) {
addedNodeLists.push(nodeList);
2014-10-18 08:01:09 +13:00
}
}
// I arbitrarily chose 250 ms for now:
// I have to compromise between the overhead of processing too few
// nodes too often and the delay of many nodes less often. There is nothing
// time critical here.
if ( addedNodeListsTimer === null ) {
addedNodeListsTimer = setTimeout(treeMutationObservedHandler, 250);
2014-10-18 08:01:09 +13:00
}
};
// This fixes http://acid3.acidtests.org/
if ( document.body ) {
// https://github.com/gorhill/httpswitchboard/issues/176
var treeObserver = new MutationObserver(treeMutationObservedHandlerAsync);
treeObserver.observe(document.body, {
2014-10-18 08:01:09 +13:00
childList: true,
subtree: true
});
}
/******************************************************************************/
})();
2015-04-12 09:15:57 +12:00
/******************************************************************************/
/******************************************************************************/
})();