aboutsummaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/freezer.js63
1 files changed, 63 insertions, 0 deletions
diff --git a/content/freezer.js b/content/freezer.js
new file mode 100644
index 0000000..cdd0709
--- /dev/null
+++ b/content/freezer.js
@@ -0,0 +1,63 @@
+/**
+ * Helper functions for blocking scripts in pages, based off NoScript's lib/DocumentFreezer.js
+ *
+ * Copyright (C) 2005-2021 Giorgio Maone - https://maone.net
+ * Copyright (C) 2021 jahoti
+ * Redistribution terms are gathered in the `copyright' file.
+ */
+
+"use strict";
+
+(() => {
+ const loaderAttributes = ["href", "src", "data"];
+ const jsOrDataUrlRx = /^(?:data:(?:[^,;]*ml|unknown-content-type)|javascript:)/i;
+
+ function sanitizeAttributes(element) {
+ if (element._frozen)
+ return;
+ let fa = [];
+ let loaders = [];
+ for (let a of element.attributes) {
+ let name = a.localName.toLowerCase();
+ if (loaderAttributes.includes(name))
+ if (jsOrDataUrlRx.test(a.value))
+ loaders.push(a);
+
+ else if (name.startsWith("on")) {
+ console.debug("Removing", a, element.outerHTML);
+ fa.push(a.cloneNode());
+ a.value = "";
+ element[name] = null;
+ }
+ }
+ if (loaders.length) {
+ for (let a of loaders) {
+ fa.push(a.cloneNode());
+ a.value = "javascript://frozen";
+ }
+ if ("contentWindow" in element)
+ element.replaceWith(element = element.cloneNode(true));
+
+ }
+ if (fa.length)
+ element._frozenAttributes = fa;
+ element._frozen = true;
+ }
+
+ function scriptSuppressor(nonce) {
+ const blockExecute = e => {
+ if (document.readyState === 'complete') {
+ removeEventListener('beforescriptexecute', blockExecute, true);
+ return;
+ }
+ else if (e.isTrusted && e.target.getAttribute('nonce') !== nonce) { // Prevent blocking of injected scripts
+ e.preventDefault();
+ console.log('Suppressed script', e.target);
+ }
+ };
+ return blockExecute;
+ };
+
+ window.scriptSuppressor = scriptSuppressor;
+ window.sanitize_attributes = sanitizeAttributes;
+})();