📝 Added entire config directory for backup purposes
This commit is contained in:
parent
4b38e59bb6
commit
9b946e2d14
11091 changed files with 1440953 additions and 0 deletions
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* NoScript Commons Library
|
||||
* Reusable building blocks for cross-browser security/privacy WebExtensions.
|
||||
* Copyright (C) 2020-2021 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 ContentScriptOnce = (() => {
|
||||
"use strict";
|
||||
|
||||
let requestMap = new Map();
|
||||
|
||||
let getId = r => r.requestId || `{r.tabId}:{r.frameId}:{r.url}`;
|
||||
|
||||
let initOnce = () => {
|
||||
let initOnce = () => {};
|
||||
|
||||
let cleanup = r => {
|
||||
let id = getId(r);
|
||||
|
||||
let scripts = requestMap.get(id);
|
||||
if (scripts) {
|
||||
window.setTimeout(() => {
|
||||
requestMap.delete(id);
|
||||
for (let s of scripts) s.unregister();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
let filter = {
|
||||
urls: ["<all_urls>"],
|
||||
types: ["main_frame", "sub_frame", "object"]
|
||||
};
|
||||
|
||||
for (let event of ["onCompleted", "onErrorOccurred"]) {
|
||||
browser.webRequest[event].addListener(cleanup, filter);
|
||||
browser.webNavigation[event].addListener(cleanup);
|
||||
}
|
||||
|
||||
browser.runtime.onMessage.addListener(({__contentScriptOnce__}, sender) => {
|
||||
if (!__contentScriptOnce__) return;
|
||||
let {requestId, tabId, frameId, url} = __contentScriptOnce__;
|
||||
let ret = false;
|
||||
if (tabId === sender.tab.id && frameId === sender.frameId && url === sender.url) {
|
||||
cleanup({requestId});
|
||||
ret = true;
|
||||
}
|
||||
return Promise.resolve(ret);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
async execute(request, options) {
|
||||
initOnce();
|
||||
let {tabId, frameId, url, requestId} = request;
|
||||
let scripts = requestMap.get(requestId);
|
||||
if (!scripts) requestMap.set(requestId, scripts = new Set());
|
||||
let match = url;
|
||||
try {
|
||||
let urlObj = new URL(url);
|
||||
if (urlObj.port) {
|
||||
urlObj.port = "";
|
||||
match = urlObj.toString();
|
||||
}
|
||||
} catch (e) {}
|
||||
let defOpts = {
|
||||
runAt: "document_start",
|
||||
matchAboutBlank: true,
|
||||
matches: [match],
|
||||
allFrames: true,
|
||||
js: [],
|
||||
};
|
||||
|
||||
options = Object.assign(defOpts, options);
|
||||
let ackMsg = {
|
||||
__contentScriptOnce__: {requestId, tabId, frameId, url}
|
||||
};
|
||||
options.js.push({
|
||||
code: `if (document.readyState !== "complete") browser.runtime.sendMessage(${JSON.stringify(ackMsg)});`
|
||||
});
|
||||
|
||||
scripts.add(await browser.contentScripts.register(options));
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* NoScript Commons Library
|
||||
* Reusable building blocks for cross-browser security/privacy WebExtensions.
|
||||
* Copyright (C) 2020-2021 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/lib/sha256.js
|
||||
// depends on /nscl/common/uuid.js
|
||||
|
||||
"use strict";
|
||||
|
||||
var DocStartInjection = (() => {
|
||||
const MSG_ID = "__DocStartInjection__";
|
||||
let repeating = !("contentScripts" in browser);
|
||||
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.all([...scriptBuilders].map(async buildScript => {
|
||||
try {
|
||||
let script = await buildScript({tabId, frameId, url});
|
||||
if (script) 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, e);
|
||||
}
|
||||
}));
|
||||
|
||||
if (scripts.size === 0) {
|
||||
debug(`DocStartInjection: no script to inject in ${url}`);
|
||||
return;
|
||||
}
|
||||
|
||||
let id = getId(request);
|
||||
|
||||
if (repeating) {
|
||||
let scriptsBlock = [...scripts].join("\n");
|
||||
let injectionId = `injection:${uuid()}:${sha256(scriptsBlock)}`;
|
||||
let args = {
|
||||
code: `(() => {
|
||||
let injectionId = ${JSON.stringify(injectionId)};
|
||||
if (document.readyState === "complete" ||
|
||||
window[injectionId] ||
|
||||
document.URL !== ${JSON.stringify(url)}
|
||||
) return window[injectionId];
|
||||
window[injectionId] = true;
|
||||
${scriptsBlock}
|
||||
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) {
|
||||
let id = getId(request);
|
||||
let args = pending.get(id);
|
||||
if (!args) return;
|
||||
let {url, tabId} = request;
|
||||
let attempts = 0, success = false;
|
||||
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...`);
|
||||
}
|
||||
let ret = await browser.tabs.executeScript(tabId, args);
|
||||
if (success = ret[0]) {
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
if (/No tab\b/.test(e.message)) {
|
||||
break;
|
||||
}
|
||||
if (!/\baccess\b/.test(e.message)) {
|
||||
console.error(e.message);
|
||||
}
|
||||
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 {
|
||||
register(scriptBuilder) {
|
||||
if (scriptBuilders.size === 0) listen(true);
|
||||
scriptBuilders.add(scriptBuilder);
|
||||
},
|
||||
unregister(scriptBuilder) {
|
||||
scriptBuilders.delete(scriptBuilder);
|
||||
if (scriptBuilders.size() === 0) listen(false);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* NoScript Commons Library
|
||||
* Reusable building blocks for cross-browser security/privacy WebExtensions.
|
||||
* Copyright (C) 2020-2021 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Wrapper around listeners on various WebExtensions
|
||||
* APIs (e.g. webRequest.on*), as a best effort to
|
||||
* let them run last by removing and re-adding them
|
||||
* on each call (swapping 2 copies because
|
||||
* addListener() calls are asynchronous).
|
||||
* Note: we rely on implementation details Like
|
||||
* listeners being called in addition order; also,
|
||||
* clients should ensure they're not called twice for
|
||||
* the same event, if that's important.
|
||||
}
|
||||
*/
|
||||
|
||||
class LastListener {
|
||||
constructor(observed, listener, ...extras) {
|
||||
this.observed = observed;
|
||||
this.listener = listener;
|
||||
this.extras = extras;
|
||||
let ww = this._wrapped = [listener, listener].map(l => {
|
||||
let w = (...args) => {
|
||||
if (this.observed.hasListener(w._other)) {
|
||||
this.observed.removeListener(w);
|
||||
} else if (this.installed) {
|
||||
this.observed.addListener(w._other, ...this.extras);
|
||||
}
|
||||
debug("Running listener", w === ww[0] ? 0 : 1, ...args);
|
||||
return this.installed ? this.listener(...args)
|
||||
: this.defaultResult;
|
||||
}
|
||||
return w;
|
||||
});
|
||||
|
||||
ww[0]._other = ww[1];
|
||||
ww[1]._other = ww[0];
|
||||
this.installed = false;
|
||||
this.defaultResult = null;
|
||||
}
|
||||
|
||||
install() {
|
||||
if (this.installed) return;
|
||||
this.observed.addListener(this._wrapped[0], ...this.extras);
|
||||
this.installed = true;
|
||||
}
|
||||
|
||||
uninstall() {
|
||||
this.installed = false;
|
||||
for (let l of this._wrapped) this.observed.removeListener(l);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* NoScript Commons Library
|
||||
* Reusable building blocks for cross-browser security/privacy WebExtensions.
|
||||
* Copyright (C) 2020-2021 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 = (() => {
|
||||
|
||||
let cache = new Map();
|
||||
|
||||
browser.tabs.onUpdated.addListener((tabId, changes, tab) => {
|
||||
cache.set(tabId, tab);
|
||||
});
|
||||
|
||||
browser.tabs.onRemoved.addListener(tabId => {
|
||||
cache.delete(tabId);
|
||||
});
|
||||
|
||||
(async () => {
|
||||
for (let tab of await browser.tabs.query({})) {
|
||||
cache.set(tab.id, tab);
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
get(tabId) {
|
||||
return cache.get(tabId);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* NoScript Commons Library
|
||||
* Reusable building blocks for cross-browser security/privacy WebExtensions.
|
||||
* Copyright (C) 2020-2021 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/>.
|
||||
*/
|
||||
|
||||
if (typeof flextabs === "function") {
|
||||
|
||||
for (let tabs of document.querySelectorAll(".flextabs")) {
|
||||
flextabs(tabs).init();
|
||||
let {id} = tabs;
|
||||
if (!id) continue;
|
||||
let storageKey = `persistentTab-${id}`;
|
||||
let rx = new RegExp(`(?:^|[#;])tab-${id}=(\\d+)(?:;|$)`);
|
||||
let current = location.hash.match(rx);
|
||||
if (!current) {
|
||||
current = localStorage && localStorage.getItem(storageKey);
|
||||
} else {
|
||||
current = current[1];
|
||||
}
|
||||
let toggles = Array.from(tabs.querySelectorAll(".flextabs__toggle"));
|
||||
let currentToggle = toggles[current && parseInt(current) || 0];
|
||||
if (currentToggle) currentToggle.click();
|
||||
for (let toggle of toggles) {
|
||||
toggle.addEventListener("click", e => {
|
||||
let currentIdx = toggles.indexOf(toggle);
|
||||
if (localStorage) localStorage.setItem(storageKey, currentIdx);
|
||||
location.hash = location.hash.split(";").filter(p => !rx.test(p))
|
||||
.concat(`tab-${id}=${currentIdx}`).join(";");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* NoScript Commons Library
|
||||
* Reusable building blocks for cross-browser security/privacy WebExtensions.
|
||||
* Copyright (C) 2020-2021 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/>.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
{
|
||||
let requiredCORS = !UA.isMozilla;
|
||||
|
||||
let enabled = new Map();
|
||||
let corsInfoCache = new Map();
|
||||
browser.tabs.onRemoved.addListener(tab => {
|
||||
enabled.delete(tab.id);
|
||||
});
|
||||
let reqKey = (frameId, destination, origin) => `${frameId}|${destination}@${origin}`;
|
||||
|
||||
browser.runtime.onMessage.addListener(
|
||||
({__prefetchCSSResources__: msg}, sender) => {
|
||||
if (!msg) return;
|
||||
let {tab, url, origin} = sender;
|
||||
if (!origin) origin = new URL(url).origin;
|
||||
let requests = enabled.get(tab.id);
|
||||
switch(msg.type) {
|
||||
case "enableCORS":
|
||||
if (!requests) {
|
||||
enabled.set(tab.id, requests = new Set());
|
||||
}
|
||||
requests.add(reqKey(sender.frameId, msg.opts.url, origin));
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
return Promise.resolve(false);
|
||||
});
|
||||
|
||||
let corsInfo = (r, forget = false) => {
|
||||
let {tabId, frameId, url, requestId} = r;
|
||||
if (corsInfoCache.has(requestId)) {
|
||||
let cached = corsInfoCache.get(requestId);
|
||||
if (forget) corsInfoCache.delete(requestId);
|
||||
return cached;
|
||||
}
|
||||
let origin = new URL(r.initiator || r.originUrl || r.documentUrl).origin;
|
||||
let destination = new URL(url).origin;
|
||||
let info;
|
||||
if (destination !== origin) {
|
||||
info = {origin};
|
||||
let requests = enabled.get(tabId);
|
||||
if (requests) {
|
||||
let key = reqKey(frameId, url, origin);
|
||||
info.authorize = requests.has(key);
|
||||
requests.delete(key);
|
||||
}
|
||||
} else {
|
||||
info = null;
|
||||
}
|
||||
corsInfoCache.set(requestId, info);
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
let allCssFilter = {
|
||||
urls: ['<all_urls>'],
|
||||
types: ['stylesheet']
|
||||
};
|
||||
|
||||
let options = ['blocking'];
|
||||
browser.webRequest.onBeforeRequest.addListener(r => {
|
||||
corsInfo(r); // needed to cache corseInfo keying by requestId, instead of URL w/ #hash
|
||||
}, allCssFilter, options);
|
||||
|
||||
options.push('requestHeaders');
|
||||
browser.webRequest.onBeforeSendHeaders.addListener(r => {
|
||||
let crossSite = corsInfo(r);
|
||||
if (!(crossSite && crossSite.authorize)) return;
|
||||
// here we try to force a cached response
|
||||
let {requestHeaders} = r;
|
||||
for (let h of requestHeaders) {
|
||||
let name = h.name.toLowerCase();
|
||||
if (name === "cache-control") {
|
||||
h.value = "max-age=604800"
|
||||
}
|
||||
}
|
||||
return {requestHeaders};
|
||||
}, allCssFilter, options);
|
||||
|
||||
options[1] = 'responseHeaders';
|
||||
if (requiredCORS) {
|
||||
options.push('extraHeaders'); // required by Chromium to handle CORS headers
|
||||
}
|
||||
|
||||
browser.webRequest.onHeadersReceived.addListener(r => {
|
||||
let crossSite = corsInfo(r);
|
||||
if (!crossSite) return;
|
||||
let {authorize, origin} = crossSite;
|
||||
let {responseHeaders} = r;
|
||||
|
||||
if (authorize && !requiredCORS) return; // on Firefox we just need caching
|
||||
|
||||
let headersPatch = Object.assign(Object.create(null), authorize
|
||||
? {
|
||||
"cache-control": "no-store",
|
||||
"vary": "origin",
|
||||
"access-control-allow-origin": origin
|
||||
}
|
||||
: {
|
||||
"cache-control": "private, max-age=604800, immutable"
|
||||
});
|
||||
|
||||
for (let h of responseHeaders) {
|
||||
let name = h.name.toLowerCase();
|
||||
if (name in headersPatch) {
|
||||
h.value = headersPatch[name];
|
||||
delete headersPatch[name];
|
||||
}
|
||||
}
|
||||
|
||||
for (let [name, value] of Object.entries(headersPatch)) {
|
||||
responseHeaders.push({name, value});
|
||||
}
|
||||
|
||||
return {responseHeaders};
|
||||
}, allCssFilter, options);
|
||||
|
||||
let cleanup = r => {
|
||||
let crossSite = corsInfo(r, true);
|
||||
if (!(crossSite && crossSite.authorize)) return;
|
||||
if (!r.fromCache) {
|
||||
debug("Warning: cross-site CSS request from CSS resource prefetching NOT from cache.");
|
||||
}
|
||||
}
|
||||
for (let ev of ["onCompleted", "onErrorOccurred"]) {
|
||||
browser.webRequest[ev].addListener(cleanup, allCssFilter);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue