diff options
Diffstat (limited to 'data/extensions/jsr@javascriptrestrictor/nscl/service')
3 files changed, 0 insertions, 416 deletions
diff --git a/data/extensions/jsr@javascriptrestrictor/nscl/service/DocStartInjection.js b/data/extensions/jsr@javascriptrestrictor/nscl/service/DocStartInjection.js deleted file mode 100644 index 65571ab..0000000 --- a/data/extensions/jsr@javascriptrestrictor/nscl/service/DocStartInjection.js +++ /dev/null @@ -1,287 +0,0 @@ -/* - * NoScript Commons Library - * Reusable building blocks for cross-browser security/privacy WebExtensions. - * Copyright (C) 2020-2024 Giorgio Maone <https://maone.net> - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - * 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 <https://www.gnu.org/licenses/>. - */ - -// depends on /nscl/common/sha256.js -// depends on /nscl/common/uuid.js - -"use strict"; - -var DocStartInjection = (() => { - const MSG_ID = "__DocStartInjection__"; - const repeating = !("contentScripts" in browser); - const mv3Callbacks = repeating && !browser.tabs.executeScript; // mv3 on Chrome - - let scriptBuilders = new Set(); - let getId = ({requestId, tabId, frameId, url}) => requestId || `${tabId}:${frameId}:${url}`; - let pending = new Map(); - - function onMessage(msg, sender) { - let payload = msg[MSG_ID]; - if (!payload) return; - let {id, tabId, frameId, url} = payload; - let ret = false; - if (tabId === sender.tab.id && frameId === sender.frameId && url === sender.url) { - end(payload, true); - ret = true; - } - return Promise.resolve(ret); - } - - async function begin(request) { - let scripts = new Set(); - let {tabId, frameId, url} = request; - if (tabId < 0 || !/^(?:(?:https?|ftp|data|blob|file):|about:blank$)/.test(url)) return; - - await Promise.allSettled([...scriptBuilders].map(async buildScript => { - let script; - try { - script = await buildScript({tabId, frameId, url}); - if (!script) return; - if (mv3Callbacks) { - if (typeof script !== "object") { - throw new Error('On MV3 only {data: jsonObject, callback: "globalFunctionName", assign: "globalScopeVarName"} injection can work!') - } - const {data, callback, assign} = script; - scripts.add({ - data, - callback, - assign, - }); - return; - } - // mv2 - scripts.add(`try { - ${typeof script === "function" ? `(${script})();` : script} - } catch (e) { - console.error("Error in DocStartInjection script", e); - }` - ); - } catch (e) { - error(`Error calling DocStartInjection scriptBuilder: buildScript ${buildScript} - script: ${script}`, e); - } - })); - - if (scripts.size === 0) { - debug(`DocStartInjection: no script to inject in ${url}`); - return; - } - - let id = getId(request); - - if (repeating) { - let injectionId = `injection:${uuid()}:${await sha256(Math.random().toString(16))}`; - let args = mv3Callbacks ? - // mv3 browser.scripting.executeScript() - { - func: (url, injectionId, scripts) => { - if (document.readyState === "complete" || - window[injectionId] || - document.URL !== url - ) return window[injectionId]; - window[injectionId] = true; - for (s of scripts) { - const {callback, assign, data} = s; - try { - if (assign && !(assign in globalThis)) { - globalThis[assign] = data; - } - if (callback) { - let cb = globalThis[callback]; - if (typeof cb == "function") { - cb.call(globalThis, data); - } else { - console.warn(`callback globalThis.${callback} is not a function (${cb}).`); - } - } - } catch (e) { - console.error(`Error in DocStartInjection script ${JSON.stringify(s)}`, e); - } - } - return document.readyState === "loading"; - }, - args: [url, injectionId, [...scripts]], - target: {tabId, frameIds: [frameId]}, - injectImmediately: true, - } : - // mv2 browser.tabs.executeScript() - { - code: `(() => { - let injectionId = ${JSON.stringify(injectionId)}; - if (document.readyState === "complete" || - window[injectionId] || - document.URL !== ${JSON.stringify(url)} - ) return window[injectionId]; - window[injectionId] = true; - ${[...scripts].join("\n")} - return document.readyState === "loading"; - })();`, - runAt: "document_start", - frameId, - }; - pending.set(id, args); - await run(request, true); - } else { - let matches = [url]; - try { - let urlObj = new URL(url); - if (urlObj.port) { - urlObj.port = ""; - matches[0] = urlObj.toString(); - } - } catch (e) {} - - let ackMsg = JSON.stringify({ - [MSG_ID]: {id, tabId, frameId, url} - }); - scripts.add(`if (document.readyState !== "complete") browser.runtime.sendMessage(${ackMsg});`); - - let options = { - js: [...scripts].map(code => ({code})), - runAt: "document_start", - matchAboutBlank: true, - matches, - allFrames: true, - }; - let current = pending.get(id); - if (current) { - current.unregister(); - } - pending.set(id, await browser.contentScripts.register(options)); - } - } - - async function run(request, repeat = false) { - const id = getId(request); - const args = pending.get(id); - if (!args) return; - let {url, tabId} = request; - let attempts = 0; - let success = false; - const execute = mv3Callbacks ? - async () => { - const ret = await browser.scripting.executeScript(args); - return ret[0].result; - } - : async() => { - const ret = await browser.tabs.executeScript(tabId, args); - return ret[0]; - }; - for (; pending.has(id);) { - attempts++; - try { - if (attempts % 1000 === 0) { - let tab = await browser.tabs.get(request.tabId); - if (tab.url !== url) { - console.error(`Tab mismatch: ${tab.url} <> ${url} (download-triggered?)`); - break; - } - console.error(`DocStartInjection at ${url} ${attempts} failed attempts so far...`); - } - if (execute()) { - success = true; - break; - } - } catch (e) { - if (/No tab\b/.test(e.message)) { - break; - } - if (!/\baccess\b/.test(e.message)) { - console.error(e.message); - } - if (!browser.tabs.executeScript) { - console.error(`MV3 fatality, cannot script tab ${tabId}! ${JSON.stringify(args)}`); - break; - } - if (attempts % 1000 === 0) { - console.error(`DocStartInjection at ${url} ${attempts} failed attempts`, e); - } - } finally { - if (!repeat) break; - } - } - pending.delete(id); - debug(`DocStartInjection at ${url}, ${attempts} attempts, success = ${success}, repeat = ${repeat}.`); - } - - function end(request, immediate = false) { - let id = getId(request); - let script = pending.get(id); - if (script) { - if (repeating) { - run(request, false); - } else { - pending.delete(id); - if (immediate) { - script.unregister(); - } else { - setTimeout(() => script.unregister(), 500); - } - } - } - } - - let listeners = { - onBeforeNavigate: begin, - onErrorOccurred: end, - onCompleted: end, - } - - function listen(enabled) { - let {webNavigation, webRequest} = browser; - let method = `${enabled ? "add" : "remove"}Listener`; - let reqFilter = {urls: ["<all_urls>"], types: ["main_frame", "sub_frame", "object"]}; - function setup(api, eventName, listener, ...args) { - let event = api[eventName]; - if (event) { - event[method].apply(event, enabled ? [listener, ...args] : [listener]); - } - } - if (repeating) { - // Just Chromium - setup(webRequest, "onResponseStarted", begin, reqFilter); - } else { - // add or remove Firefox's webNavigation listeners for non-http loads - // and asynchronous blocking onHeadersReceived for registration on http - let navFilter = enabled && {url: [{schemes: ["file", "ftp"]}]}; - for (let [eventName, listener] of Object.entries(listeners)) { - setup(webNavigation, eventName, listener, navFilter) - } - setup(webRequest, "onHeadersReceived", begin, reqFilter, ["blocking"]); - browser.runtime.onMessage[method](onMessage); - } - - // add or remove common webRequest listener - for (let [eventName, listener] of Object.entries(listeners)) { - setup(webRequest, eventName, listener, reqFilter); - } - } - - return { - mv3Callbacks, - register(scriptBuilder) { - if (scriptBuilders.size === 0) listen(true); - scriptBuilders.add(scriptBuilder); - }, - unregister(scriptBuilder) { - scriptBuilders.delete(scriptBuilder); - if (scriptBuilders.size === 0) listen(false); - } - }; -})();
\ No newline at end of file diff --git a/data/extensions/jsr@javascriptrestrictor/nscl/service/NavCache.js b/data/extensions/jsr@javascriptrestrictor/nscl/service/NavCache.js deleted file mode 100644 index 28bdb0d..0000000 --- a/data/extensions/jsr@javascriptrestrictor/nscl/service/NavCache.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * NoScript Commons Library - * Reusable building blocks for cross-browser security/privacy WebExtensions. - * Copyright (C) 2020-2024 Giorgio Maone <https://maone.net> - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - * 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 <https://www.gnu.org/licenses/>. - */ - -var NavCache = (() => { - - let tabs = {}; - let listeners = new Set(); - - let clone = structuredClone || (o => JSON.parse(JSON.stringify(o))); - - browser.webNavigation.onCommitted.addListener(({tabId, frameId, url, parentFrameId}) => { - let tab = tabs[tabId]; - let frame = tab && tab[frameId]; - if (!tab || frameId == 0) { - tabs[tabId] = tab = {}; - } - let previousUrl = frame && frame.url; - frame = tab[frameId] = {previousUrl, url, parentFrameId}; - if (previousUrl !== url) { - for (let l of listeners) { - try { - l(Object.assign({tabId, frameId}, frame)); - } catch (e) { - console.error(e); - } - } - } - }); - - browser.tabs.onRemoved.addListener(tabId => { - delete tabs[tabId]; - }); - - - return { - wakening: (async () => { - async function populateFrames(tab) { - let tabId = tab.id; - let frames = await browser.webNavigation.getAllFrames({tabId}); - if (!frames) return; // invalid tab - if (!tabs[tabId]) tabs[tabId] = {}; - let top = tabs[tabId]; - for ({frameId, url, parentFrameId} of frames) { - tab[frameId] = {url, parentFrameId}; - } - } - await Promise.all((await browser.tabs.query({})).map(populateFrames)); - return true; - })(), - - getTab(tabId) { - return clone(tabs[tabId] || {}); - }, - getFrame(tabId, frameId) { - return clone((tabs[tabId] || {})[frameId]); - }, - onUrlChanged: { - addListener(listener) { - listeners.add(listener); - }, - removeListener(listener) { - listeners.remove(listeners); - } - } - }; -})(); diff --git a/data/extensions/jsr@javascriptrestrictor/nscl/service/TabCache.js b/data/extensions/jsr@javascriptrestrictor/nscl/service/TabCache.js deleted file mode 100644 index eb290f0..0000000 --- a/data/extensions/jsr@javascriptrestrictor/nscl/service/TabCache.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * NoScript Commons Library - * Reusable building blocks for cross-browser security/privacy WebExtensions. - * Copyright (C) 2020-2024 Giorgio Maone <https://maone.net> - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - * 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 <https://www.gnu.org/licenses/>. - */ - -var TabCache = (() => { - - const cache = new Map(); - - browser.tabs.onUpdated.addListener((tabId, changes, tab) => { - cache.set(tabId, tab); - }); - - browser.tabs.onRemoved.addListener(tabId => { - cache.delete(tabId); - }); - - return { - wakening: (async () => { - for (let tab of await browser.tabs.query({})) { - cache.set(tab.id, tab); - } - })(), - get(tabId) { - return cache.get(tabId); - }, - async async(tabId) { - return cache.get(tabId) || await browser.tabs.get(tabId); - } - }; -})(); |