aboutsummaryrefslogtreecommitdiffstats
path: root/js/contentscript.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/contentscript.js')
-rw-r--r--js/contentscript.js558
1 files changed, 279 insertions, 279 deletions
diff --git a/js/contentscript.js b/js/contentscript.js
index 21fbcf1..9fb15f8 100644
--- a/js/contentscript.js
+++ b/js/contentscript.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
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
@@ -17,7 +17,7 @@
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://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -29,54 +29,54 @@
// https://github.com/chrisaljoudi/uBlock/issues/464
// https://github.com/gorhill/uMatrix/issues/621
if (document instanceof HTMLDocument === false
- && document instanceof XMLDocument === false) {
- return;
+ && document instanceof XMLDocument === false) {
+ return;
}
// This can also happen (for example if script injected into a
// `data:` URI doc)
if (!window.location) {
- return;
+ return;
}
// This can happen
if (typeof vAPI !== 'object') {
- //console.debug('contentscript.js > vAPI not found');
- return;
+ //console.debug('contentscript.js > vAPI not found');
+ return;
}
// https://github.com/chrisaljoudi/uBlock/issues/456
// Already injected?
if (vAPI.contentscriptEndInjected) {
- //console.debug('contentscript.js > content script already injected');
- return;
+ //console.debug('contentscript.js > content script already injected');
+ return;
}
vAPI.contentscriptEndInjected = true;
// Executed only once.
(function () {
- let localStorageHandler = function (mustRemove) {
+ let localStorageHandler = function (mustRemove) {
if (mustRemove) {
- window.localStorage.clear();
- window.sessionStorage.clear();
+ window.localStorage.clear();
+ window.sessionStorage.clear();
}
- };
+ };
- // 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 {
+ // 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 {
let hasLocalStorage =
- window.localStorage && window.localStorage.length !== 0;
+ window.localStorage && window.localStorage.length !== 0;
let hasSessionStorage =
- window.sessionStorage && window.sessionStorage.length !== 0;
+ window.sessionStorage && window.sessionStorage.length !== 0;
if (hasLocalStorage || hasSessionStorage) {
- vAPI.messaging.send('contentscript.js', {
+ vAPI.messaging.send('contentscript.js', {
what: 'contentScriptHasLocalStorage',
originURL: window.location.origin
- }, localStorageHandler);
+ }, localStorageHandler);
}
// TODO: indexedDB
@@ -92,13 +92,13 @@
// "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) {
- }
+ } catch (e) {
+ }
})();
// https://github.com/gorhill/uMatrix/issues/45
let collapser = (function () {
- let resquestIdGenerator = 1;
+ let resquestIdGenerator = 1;
let processTimer;
let toProcess = [];
let toFilter = [];
@@ -107,320 +107,320 @@
let cachedBlockedMapHash;
let cachedBlockedMapTimer;
let reURLPlaceholder = /\{\{url\}\}/g;
- let src1stProps = {
+ let src1stProps = {
embed: 'src',
iframe: 'src',
img: 'src',
object: 'data',
- };
- let src2ndProps = {
+ };
+ let src2ndProps = {
img: 'srcset',
- };
- let tagToTypeMap = {
+ };
+ let tagToTypeMap = {
embed: 'media',
iframe: 'frame',
img: 'image',
object: 'media',
- };
- let cachedBlockedSetClear = function () {
+ };
+ let cachedBlockedSetClear = function () {
cachedBlockedMap =
- cachedBlockedMapHash =
- cachedBlockedMapTimer = undefined;
- };
+ cachedBlockedMapHash =
+ cachedBlockedMapTimer = undefined;
+ };
- // https://github.com/chrisaljoudi/uBlock/issues/174
- // Do not remove fragment from src URL
- let onProcessed = function (response) {
+ // https://github.com/chrisaljoudi/uBlock/issues/174
+ // Do not remove fragment from src URL
+ let onProcessed = function (response) {
if (!response) { // This happens if uBO is disabled or restarted.
- toCollapse.clear();
- return;
+ toCollapse.clear();
+ return;
}
let targets = toCollapse.get(response.id);
if (targets === undefined) {
- return;
- }
+ return;
+ }
toCollapse.delete(response.id);
if (cachedBlockedMapHash !== response.hash) {
- cachedBlockedMap = new Map(response.blockedResources);
- cachedBlockedMapHash = response.hash;
- if (cachedBlockedMapTimer !== undefined) {
+ cachedBlockedMap = new Map(response.blockedResources);
+ cachedBlockedMapHash = response.hash;
+ if (cachedBlockedMapTimer !== undefined) {
clearTimeout(cachedBlockedMapTimer);
- }
- cachedBlockedMapTimer =
- vAPI.setTimeout(cachedBlockedSetClear, 30000);
+ }
+ cachedBlockedMapTimer =
+ vAPI.setTimeout(cachedBlockedSetClear, 30000);
}
if (cachedBlockedMap === undefined || cachedBlockedMap.size === 0) {
- return;
+ return;
}
let placeholders = response.placeholders;
for (let target of targets) {
- let tag = target.localName;
+ let tag = target.localName;
- let prop = src1stProps[tag];
- if (prop === undefined) {
- continue;
- }
+ let prop = src1stProps[tag];
+ if (prop === undefined) {
+ continue;
+ }
- let src = target[prop];
- if (typeof src !== 'string' || src.length === 0) {
+ let src = target[prop];
+ if (typeof src !== 'string' || src.length === 0) {
prop = src2ndProps[tag];
if (prop === undefined) {
- continue;
- }
+ continue;
+ }
src = target[prop];
if (typeof src !== 'string' || src.length === 0) {
- continue;
- }
- }
-
- let collapsed = cachedBlockedMap.get(tagToTypeMap[tag]
- + ' '
- + src);
- if (collapsed === undefined) {
- continue;
- }
-
- if (collapsed) {
+ continue;
+ }
+ }
+
+ let collapsed = cachedBlockedMap.get(tagToTypeMap[tag]
+ + ' '
+ + src);
+ if (collapsed === undefined) {
+ continue;
+ }
+
+ if (collapsed) {
target.style.setProperty('display', 'none', 'important');
target.hidden = true;
continue;
- }
+ }
- switch (tag) {
- case 'iframe':
+ switch (tag) {
+ case 'iframe':
if (placeholders.frame !== true) {
- break;
- }
+ break;
+ }
let docurl = 'data:text/html,'
- + encodeURIComponent(placeholders
- .frameDocument
- .replace(reURLPlaceholder, src));
+ + encodeURIComponent(placeholders
+ .frameDocument
+ .replace(reURLPlaceholder, src));
let replaced = false;
// Using contentWindow.location prevent tainting browser
// history -- i.e. breaking back button (seen on Chromium).
if (target.contentWindow) {
- try {
+ try {
target.contentWindow.location.replace(docurl);
replaced = true;
- } catch(ex) {
- }
+ } catch(ex) {
+ }
}
if (!replaced) {
- target.setAttribute('src', docurl);
+ target.setAttribute('src', docurl);
}
break;
- case 'img':
+ case 'img':
if (placeholders.image !== true) {
- break;
- }
+ break;
+ }
target.style.setProperty('display', 'inline-block');
target.style.setProperty('min-width', '20px', 'important');
target.style.setProperty('min-height', '20px', 'important');
target.style.setProperty('border', placeholders.imageBorder,
- 'important');
+ 'important');
target.style.setProperty('background',
- placeholders.imageBackground,
- 'important');
+ placeholders.imageBackground,
+ 'important');
break;
- }
+ }
}
- };
+ };
- let send = function () {
+ let send = function () {
processTimer = undefined;
toCollapse.set(resquestIdGenerator, toProcess);
let msg = {
- what: 'lookupBlockedCollapsibles',
- id: resquestIdGenerator,
- toFilter: toFilter,
- hash: cachedBlockedMapHash
+ what: 'lookupBlockedCollapsibles',
+ id: resquestIdGenerator,
+ toFilter: toFilter,
+ hash: cachedBlockedMapHash
};
vAPI.messaging.send('contentscript.js', msg, onProcessed);
toProcess = [];
toFilter = [];
resquestIdGenerator += 1;
- };
+ };
- let process = function (delay) {
+ let process = function (delay) {
if (toProcess.length === 0) {
- return;
- }
+ return;
+ }
if (delay === 0) {
- if (processTimer !== undefined) {
+ if (processTimer !== undefined) {
clearTimeout(processTimer);
- }
- send();
+ }
+ send();
} else if (processTimer === undefined) {
- processTimer = vAPI.setTimeout(send, delay || 47);
+ processTimer = vAPI.setTimeout(send, delay || 47);
}
- };
+ };
- let add = function (target) {
+ let add = function (target) {
toProcess.push(target);
- };
+ };
- let addMany = function (targets) {
- for (let i=targets.length-1; i>=0; --i) {
- toProcess.push(targets[i]);
+ let addMany = function (targets) {
+ for (let i=targets.length-1; i>=0; --i) {
+ toProcess.push(targets[i]);
}
- };
+ };
- let iframeSourceModified = function (mutations) {
- for (let i=mutations.length-1; i>=0; --i) {
- addIFrame(mutations[i].target, true);
+ let iframeSourceModified = function (mutations) {
+ for (let i=mutations.length-1; i>=0; --i) {
+ addIFrame(mutations[i].target, true);
}
process();
- };
+ };
- let iframeSourceObserver;
- let iframeSourceObserverOptions = {
+ let iframeSourceObserver;
+ let iframeSourceObserverOptions = {
attributes: true,
attributeFilter: [ 'src' ]
- };
+ };
- let addIFrame = function (iframe, dontObserve) {
+ let addIFrame = function (iframe, dontObserve) {
// https://github.com/gorhill/uBlock/issues/162
// Be prepared to deal with possible change of src attribute.
if (dontObserve !== true) {
- if (iframeSourceObserver === undefined) {
+ if (iframeSourceObserver === undefined) {
iframeSourceObserver =
- new MutationObserver(iframeSourceModified);
- }
- iframeSourceObserver.observe(iframe,
- iframeSourceObserverOptions);
+ new MutationObserver(iframeSourceModified);
+ }
+ iframeSourceObserver.observe(iframe,
+ iframeSourceObserverOptions);
}
let src = iframe.src;
if (src === '' || typeof src !== 'string') {
- return;
- }
+ return;
+ }
if (src.startsWith('http') === false) {
- return;
- }
+ return;
+ }
toFilter.push({
- type: 'frame',
- url: iframe.src,
- });
+ type: 'frame',
+ url: iframe.src,
+ });
add(iframe);
- };
+ };
- let addIFrames = function (iframes) {
- for (let i=iframes.length-1; i>=0; --i) {
- addIFrame(iframes[i]);
+ let addIFrames = function (iframes) {
+ for (let i=iframes.length-1; i>=0; --i) {
+ addIFrame(iframes[i]);
}
- };
-
- let addNodeList = function (nodeList) {
- for (let i=nodeList.length-1; i>=0; --i) {
- let node = nodeList[i];
- if (node.nodeType !== 1) {
- continue;
- }
- if (node.localName === 'iframe') {
+ };
+
+ let addNodeList = function (nodeList) {
+ for (let i=nodeList.length-1; i>=0; --i) {
+ let node = nodeList[i];
+ if (node.nodeType !== 1) {
+ continue;
+ }
+ if (node.localName === 'iframe') {
addIFrame(node);
- }
- if (node.childElementCount !== 0) {
+ }
+ if (node.childElementCount !== 0) {
addIFrames(node.querySelectorAll('iframe'));
- }
+ }
}
- };
+ };
- let onResourceFailed = function (ev) {
+ let onResourceFailed = function (ev) {
if (tagToTypeMap[ev.target.localName] !== undefined) {
- add(ev.target);
- process();
+ add(ev.target);
+ process();
}
- };
- document.addEventListener('error', onResourceFailed, true);
+ };
+ document.addEventListener('error', onResourceFailed, true);
- vAPI.shutdown.add(function () {
+ vAPI.shutdown.add(function () {
document.removeEventListener('error', onResourceFailed, true);
if (iframeSourceObserver !== undefined) {
- iframeSourceObserver.disconnect();
- iframeSourceObserver = undefined;
+ iframeSourceObserver.disconnect();
+ iframeSourceObserver = undefined;
}
if (processTimer !== undefined) {
- clearTimeout(processTimer);
- processTimer = undefined;
+ clearTimeout(processTimer);
+ processTimer = undefined;
}
- });
+ });
- return {
+ return {
addMany: addMany,
addIFrames: addIFrames,
addNodeList: addNodeList,
process: process
- };
+ };
})();
// Observe changes in the DOM
// Added node lists will be cumulated here before being processed
(function () {
- // This fixes http://acid3.acidtests.org/
- if (!document.body) {
- return;
- }
+ // This fixes http://acid3.acidtests.org/
+ if (!document.body) {
+ return;
+ }
- let addedNodeLists = [];
- let addedNodeListsTimer;
+ let addedNodeLists = [];
+ let addedNodeListsTimer;
- let treeMutationObservedHandler = function () {
+ let treeMutationObservedHandler = function () {
addedNodeListsTimer = undefined;
- for (let i=addedNodeLists.length-1; i>=0; --i) {
- collapser.addNodeList(addedNodeLists[i]);
+ for (let i=addedNodeLists.length-1; i>=0; --i) {
+ collapser.addNodeList(addedNodeLists[i]);
}
collapser.process();
addedNodeLists = [];
- };
-
- // https://github.com/gorhill/uBlock/issues/205
- // Do not handle added node directly from within mutation observer.
- let treeMutationObservedHandlerAsync = function (mutations) {
- for (let i=mutations.length-1; i>=0; --i) {
- let nodeList = mutations[i].addedNodes;
- if (nodeList.length !== 0) {
+ };
+
+ // https://github.com/gorhill/uBlock/issues/205
+ // Do not handle added node directly from within mutation observer.
+ let treeMutationObservedHandlerAsync = function (mutations) {
+ for (let i=mutations.length-1; i>=0; --i) {
+ let nodeList = mutations[i].addedNodes;
+ if (nodeList.length !== 0) {
addedNodeLists.push(nodeList);
- }
+ }
}
if (addedNodeListsTimer === undefined) {
- addedNodeListsTimer =
- vAPI.setTimeout(treeMutationObservedHandler, 47);
+ addedNodeListsTimer =
+ vAPI.setTimeout(treeMutationObservedHandler, 47);
}
- };
+ };
- // https://github.com/gorhill/httpswitchboard/issues/176
- let treeObserver =
- new MutationObserver(treeMutationObservedHandlerAsync);
- treeObserver.observe(document.body, {
+ // https://github.com/gorhill/httpswitchboard/issues/176
+ let treeObserver =
+ new MutationObserver(treeMutationObservedHandlerAsync);
+ treeObserver.observe(document.body, {
childList: true,
subtree: true
- });
+ });
- vAPI.shutdown.add(function () {
+ vAPI.shutdown.add(function () {
if (addedNodeListsTimer !== undefined) {
- clearTimeout(addedNodeListsTimer);
- addedNodeListsTimer = undefined;
+ clearTimeout(addedNodeListsTimer);
+ addedNodeListsTimer = undefined;
}
if (treeObserver !== null) {
- treeObserver.disconnect();
- treeObserver = undefined;
+ treeObserver.disconnect();
+ treeObserver = undefined;
}
addedNodeLists = [];
- });
+ });
})();
// Executed only once.
@@ -437,58 +437,58 @@
// Report inline styles.
(function () {
- if (document.querySelector('script:not([src])') !== null
- || document.querySelector('a[href^="javascript:"]') !== null
- || document.querySelector('[onabort],[onblur],[oncancel],'
- + '[oncanplay],[oncanplaythrough],'
- + '[onchange],[onclick],[onclose],'
- + '[oncontextmenu],[oncuechange],'
- + '[ondblclick],[ondrag],[ondragend],'
- + '[ondragenter],[ondragexit],'
- + '[ondragleave],[ondragover],'
- + '[ondragstart],[ondrop],'
- + '[ondurationchange],[onemptied],'
- + '[onended],[onerror],[onfocus],'
- + '[oninput],[oninvalid],[onkeydown],'
- + '[onkeypress],[onkeyup],[onload],'
- + '[onloadeddata],[onloadedmetadata],'
- + '[onloadstart],[onmousedown],'
- + '[onmouseenter],[onmouseleave],'
- + '[onmousemove],[onmouseout],'
- + '[onmouseover],[onmouseup],[onwheel],'
- + '[onpause],[onplay],[onplaying],'
- + '[onprogress],[onratechange],[onreset],'
- + '[onresize],[onscroll],[onseeked],'
- + '[onseeking],[onselect],[onshow],'
- + '[onstalled],[onsubmit],[onsuspend],'
- + '[ontimeupdate],[ontoggle],'
- + '[onvolumechange],[onwaiting],'
- + '[onafterprint],[onbeforeprint],'
- + '[onbeforeunload],[onhashchange],'
- + '[onlanguagechange],[onmessage],'
- + '[onoffline],[ononline],[onpagehide],'
- + '[onpageshow],[onrejectionhandled],'
- + '[onpopstate],[onstorage],'
- + '[onunhandledrejection],[onunload],'
- + '[oncopy],[oncut],[onpaste]') !== null) {
+ if (document.querySelector('script:not([src])') !== null
+ || document.querySelector('a[href^="javascript:"]') !== null
+ || document.querySelector('[onabort],[onblur],[oncancel],'
+ + '[oncanplay],[oncanplaythrough],'
+ + '[onchange],[onclick],[onclose],'
+ + '[oncontextmenu],[oncuechange],'
+ + '[ondblclick],[ondrag],[ondragend],'
+ + '[ondragenter],[ondragexit],'
+ + '[ondragleave],[ondragover],'
+ + '[ondragstart],[ondrop],'
+ + '[ondurationchange],[onemptied],'
+ + '[onended],[onerror],[onfocus],'
+ + '[oninput],[oninvalid],[onkeydown],'
+ + '[onkeypress],[onkeyup],[onload],'
+ + '[onloadeddata],[onloadedmetadata],'
+ + '[onloadstart],[onmousedown],'
+ + '[onmouseenter],[onmouseleave],'
+ + '[onmousemove],[onmouseout],'
+ + '[onmouseover],[onmouseup],[onwheel],'
+ + '[onpause],[onplay],[onplaying],'
+ + '[onprogress],[onratechange],[onreset],'
+ + '[onresize],[onscroll],[onseeked],'
+ + '[onseeking],[onselect],[onshow],'
+ + '[onstalled],[onsubmit],[onsuspend],'
+ + '[ontimeupdate],[ontoggle],'
+ + '[onvolumechange],[onwaiting],'
+ + '[onafterprint],[onbeforeprint],'
+ + '[onbeforeunload],[onhashchange],'
+ + '[onlanguagechange],[onmessage],'
+ + '[onoffline],[ononline],[onpagehide],'
+ + '[onpageshow],[onrejectionhandled],'
+ + '[onpopstate],[onstorage],'
+ + '[onunhandledrejection],[onunload],'
+ + '[oncopy],[oncut],[onpaste]') !== null) {
vAPI.messaging.send('contentscript.js', {
- what: 'securityPolicyViolation',
- directive: 'script-src',
- documentURI: window.location.href
+ what: 'securityPolicyViolation',
+ directive: 'script-src',
+ documentURI: window.location.href
});
- }
+ }
- if (document.querySelector('style,[style]') !== null) {
+ if (document.querySelector('style,[style]') !== null) {
vAPI.messaging.send('contentscript.js', {
- what: 'securityPolicyViolation',
- directive: 'style-src',
- documentURI: window.location.href
+ what: 'securityPolicyViolation',
+ directive: 'style-src',
+ documentURI: window.location.href
});
- }
+ }
- collapser.addMany(document.querySelectorAll('img'));
- collapser.addIFrames(document.querySelectorAll('iframe'));
- collapser.process();
+ collapser.addMany(document.querySelectorAll('img'));
+ collapser.addIFrames(document.querySelectorAll('iframe'));
+ collapser.process();
})();
// Executed only once.
@@ -496,88 +496,88 @@
// Force `display` property, Firefox is still affected by the issue.
(function () {
- let noscripts = document.querySelectorAll('noscript');
- if (noscripts.length === 0) {
- return;
- }
+ let noscripts = document.querySelectorAll('noscript');
+ if (noscripts.length === 0) {
+ return;
+ }
- let redirectTimer;
+ let redirectTimer;
let reMetaContent = /^\s*(\d+)\s*;\s*url=(['"]?)([^'"]+)\2/i;
let reSafeURL = /^https?:\/\//;
- let autoRefresh = function (root) {
+ let autoRefresh = function (root) {
let meta =
- root.querySelector('meta[http-equiv="refresh"][content]');
+ root.querySelector('meta[http-equiv="refresh"][content]');
if (meta === null) {
- return;
- }
+ return;
+ }
let match = reMetaContent.exec(meta.getAttribute('content'));
if (match === null || match[3].trim() === '') {
- return;
- }
+ return;
+ }
let url = new URL(match[3], document.baseURI);
if (reSafeURL.test(url.href) === false) {
- return;
- }
+ return;
+ }
redirectTimer = setTimeout(function () {
location.assign(url.href);
- }, parseInt(match[1], 10) * 1000 + 1);
+ }, parseInt(match[1], 10) * 1000 + 1);
meta.parentNode.removeChild(meta);
- };
+ };
- let morphNoscript = function (from) {
+ let morphNoscript = function (from) {
if (/^application\/(?:xhtml\+)?xml/.test(document.contentType)) {
- let to = document.createElement('span');
- while (from.firstChild !== null) {
+ let to = document.createElement('span');
+ while (from.firstChild !== null) {
to.appendChild(from.firstChild);
- }
- return to;
+ }
+ return to;
}
let parser = new DOMParser();
let doc =
- parser.parseFromString('<span>' + from.textContent + '</span>',
- 'text/html');
+ parser.parseFromString('<span>' + from.textContent + '</span>',
+ 'text/html');
return document.adoptNode(doc.querySelector('span'));
- };
+ };
- let renderNoscriptTags = function (response) {
+ let renderNoscriptTags = function (response) {
if (response !== true) {
- return;
- }
+ return;
+ }
for (let noscript of noscripts) {
- let parent = noscript.parentNode;
- if (parent === null) {
- continue;
- }
+ let parent = noscript.parentNode;
+ if (parent === null) {
+ continue;
+ }
- let span = morphNoscript(noscript);
- span.style.setProperty('display', 'inline', 'important');
+ let span = morphNoscript(noscript);
+ span.style.setProperty('display', 'inline', 'important');
- if (redirectTimer === undefined) {
+ if (redirectTimer === undefined) {
autoRefresh(span);
- }
+ }
- parent.replaceChild(span, noscript);
+ parent.replaceChild(span, noscript);
}
- };
+ };
- vAPI.messaging.send('contentscript.js', {
- what: 'mustRenderNoscriptTags?'
- }, renderNoscriptTags);
+ vAPI.messaging.send('contentscript.js', {
+ what: 'mustRenderNoscriptTags?'
+ }, renderNoscriptTags);
})();
vAPI.messaging.send('contentscript.js', {
- what: 'shutdown?'
+ what: 'shutdown?'
}, function (response) {
if (response === true) {
- vAPI.shutdown.exec();
+ vAPI.shutdown.exec();
}
});
})();