From 6cf97fd38db966f07d735fdd76f2d0a00c708dcd Mon Sep 17 00:00:00 2001 From: claustromaniac <20734810+claustromaniac@users.noreply.github.com> Date: Thu, 17 Jan 2019 18:34:58 -0300 Subject: [PATCH] optimizations --- src/bg/classes.js | 5 +- src/bg/globals.js | 2 + src/bg/runtime.js | 2 + src/bg/tabs.js | 2 + src/bg/webRequest.js | 293 +++++++++++++++++++++--------------------- src/pages/misc.js | 6 - src/pages/options.htm | 4 +- src/pages/options.js | 77 ++++++----- src/pages/popup.htm | 4 +- src/pages/popup.js | 172 ++++++++++++------------- 10 files changed, 281 insertions(+), 286 deletions(-) diff --git a/src/bg/classes.js b/src/bg/classes.js index 9512c6f..0824ed5 100644 --- a/src/bg/classes.js +++ b/src/bg/classes.js @@ -22,10 +22,11 @@ class Settings { } }; this.loading = (async () => { - let saved = await browser.storage.local.get(this.defaults); + const local = browser.storage.local; + let saved = await local.get(this.defaults); if (!Array.isArray(saved.overrides)) saved.overrides = []; this.all = saved; - await browser.storage.local.set(saved); + await local.set(saved); browser.storage.onChanged.addListener((changes, area) => { console.debug(`Privacy-Oriented Origin Policy: ${area} storage changed`); for (const i in changes) { diff --git a/src/bg/globals.js b/src/bg/globals.js index 86bcfcb..0f4b3c3 100644 --- a/src/bg/globals.js +++ b/src/bg/globals.js @@ -1,3 +1,5 @@ +'use strict'; + const settings = new Settings(); const popup = new Popup(); const tabs = new Tabs(); diff --git a/src/bg/runtime.js b/src/bg/runtime.js index e4b323f..07b1c29 100644 --- a/src/bg/runtime.js +++ b/src/bg/runtime.js @@ -1,3 +1,5 @@ +'use strict'; + browser.runtime.onConnect.addListener(port => { port.onMessage.addListener(msg => { popup.start(msg, port); diff --git a/src/bg/tabs.js b/src/bg/tabs.js index c23f92c..72453fe 100644 --- a/src/bg/tabs.js +++ b/src/bg/tabs.js @@ -1,2 +1,4 @@ +'use strict'; + browser.tabs.onRemoved.addListener((tabId, removeInfo) => { delete tabs[tabId] }); browser.tabs.onReplaced.addListener((newId, oldId) => { delete tabs[oldId] }); diff --git a/src/bg/webRequest.js b/src/bg/webRequest.js index e442c52..695f492 100644 --- a/src/bg/webRequest.js +++ b/src/bg/webRequest.js @@ -1,157 +1,156 @@ -(() => { - 'use strict'; - const acao = {name: 'Access-Control-Allow-Origin', value: '*'}; - const filter = {urls: [""]}; - const rIDs = {}; // tab objs by request ID - const getRoot = host => { - const parts = host.split('.'); - let root; - while (parts.length > 1) { - root = parts.shift(); - if (publicSuffixes.has(parts.join('.'))) break; - } - return root; - }; - const isExcluded = (origin, target) => { - const arr = settings.exclusions; - for (const e of arr) { - if (e.origin.includes('*')) { - const rx = new RegExp(e.origin); - if (!rx.test(origin)) continue; - } else if (e.origin !== origin) continue; - if (e.target.includes('*')) { - const rx = new RegExp(e.target); - if (!rx.test(target)) continue; - } else if (e.target !== target) continue; - return true; - } - }; +'use strict'; - browser.webRequest.onBeforeSendHeaders.addListener(d => { - if (d.tabId === -1 || !d.requestHeaders) return; - if (d.type === 'main_frame') { - delete rIDs[d.requestId]; - delete tabs[d.tabId]; - const info = tabs.getInfo(d.tabId); - info.url = d.url; - return; - } - if ( - (d.method !== 'GET' && d.method !== 'OPTIONS') || - !settings.enabled - ) return; +const acao = {name: 'Access-Control-Allow-Origin', value: '*'}; +const filter = {urls: [""]}; +const rIDs = {}; // tab objs by request ID +const getRoot = host => { + const parts = host.split('.'); + let root; + while (parts.length > 1) { + root = parts.shift(); + if (publicSuffixes.has(parts.join('.'))) break; + } + return root; +}; +const isExcluded = (origin, target) => { + const arr = settings.exclusions; + for (const e of arr) { + if (e.origin.includes('*')) { + const rx = new RegExp(e.origin); + if (!rx.test(origin)) continue; + } else if (e.origin !== origin) continue; + if (e.target.includes('*')) { + const rx = new RegExp(e.target); + if (!rx.test(target)) continue; + } else if (e.target !== target) continue; + return true; + } +}; + +browser.webRequest.onBeforeSendHeaders.addListener(d => { + if (d.tabId === -1 || !d.requestHeaders) return; + if (d.type === 'main_frame') { + delete rIDs[d.requestId]; + delete tabs[d.tabId]; const info = tabs.getInfo(d.tabId); - const mode = info.getMode(); - if (!mode) return; - const target = new URL(d.url); - if ( - mode === 1 && - !settings.strictTypes[d.type] && ( - target.searchParams || - target.hash || - target.username || - target.password - ) - ) return; + info.url = d.url; + return; + } + if ( + (d.method !== 'GET' && d.method !== 'OPTIONS') || + !settings.enabled + ) return; + const info = tabs.getInfo(d.tabId); + const mode = info.getMode(); + if (!mode) return; + const target = new URL(d.url); + if ( + mode === 1 && + !settings.strictTypes[d.type] && ( + target.searchParams || + target.hash || + target.username || + target.password + ) + ) return; - const newHeaders = []; - let origin; - let referer; - let acrm; // Access-Control-Request-Method - for (const header of d.requestHeaders) { - switch (header.name.toLowerCase()) { - case 'cookie': - if (mode === 1 && !settings.strictTypes[d.type]) return; - newHeaders.push(header); - break; - case 'referer': - referer = header; - break; - case 'origin': - if (settings.rdExclusions) { - const temp = (new URL(header.value)).hostname; - if (getRoot(temp) === getRoot(target.hostname)) { - console.debug( - `Privacy-Oriented Origin Policy: request #${d.requestId} skipped. Reason: root domains match\n${header.value}\n${d.url}` - ); - return; - } + const newHeaders = []; + let origin; + let referer; + let acrm; // Access-Control-Request-Method + for (const header of d.requestHeaders) { + switch (header.name.toLowerCase()) { + case 'cookie': + if (mode === 1 && !settings.strictTypes[d.type]) return; + newHeaders.push(header); + break; + case 'referer': + referer = header; + break; + case 'origin': + if (settings.rdExclusions) { + const temp = (new URL(header.value)).hostname; + if (getRoot(temp) === getRoot(target.hostname)) { + console.debug( + `Privacy-Oriented Origin Policy: request #${d.requestId} skipped. Reason: root domains match\n${header.value}\n${d.url}` + ); + return; } - if (settings.exclusions.length) { - const temp = (new URL(header.value)).hostname; - if (isExcluded(temp, target.hostname)) { - console.debug( - `Privacy-Oriented Origin Policy: request #${d.requestId} skipped. Reason: exclusion rule matched` - ); - return; - } + } + if (settings.exclusions.length) { + const temp = (new URL(header.value)).hostname; + if (isExcluded(temp, target.hostname)) { + console.debug( + `Privacy-Oriented Origin Policy: request #${d.requestId} skipped. Reason: exclusion rule matched` + ); + return; } - origin = `Origin ${header.value}`; - break; - case 'authorization': - if (mode === 1 && !settings.strictTypes[d.type]) return; - newHeaders.push(header); - break; - case 'access-control-request-method': - if (header.value !== 'GET') return; - acrm = true; - newHeaders.push(header); - break; - default: - newHeaders.push(header); - } + } + origin = `Origin ${header.value}`; + break; + case 'authorization': + if (mode === 1 && !settings.strictTypes[d.type]) return; + newHeaders.push(header); + break; + case 'access-control-request-method': + if (header.value !== 'GET') return; + acrm = true; + newHeaders.push(header); + break; + default: + newHeaders.push(header); } - if (origin) { - if (d.method == 'OPTIONS' && !acrm) return; - if (referer) { - if (settings.referers) { - newHeaders.push({name:'Referer', value:`${d.url}`}); - console.debug( - `Privacy-Oriented Origin Policy: Referer spoofed (request #${d.requestId})\n${d.url}` - ); - } else newHeaders.push(referer); - } - console.debug(`Privacy-Oriented Origin Policy: ${origin} removed from request #${d.requestId}`); - rIDs[d.requestId] = info; - return {requestHeaders: newHeaders}; + } + if (origin) { + if (d.method == 'OPTIONS' && !acrm) return; + if (referer) { + if (settings.referers) { + newHeaders.push({name:'Referer', value:`${d.url}`}); + console.debug( + `Privacy-Oriented Origin Policy: Referer spoofed (request #${d.requestId})\n${d.url}` + ); + } else newHeaders.push(referer); } - }, filter, ['blocking', 'requestHeaders']); + console.debug(`Privacy-Oriented Origin Policy: ${origin} removed from request #${d.requestId}`); + rIDs[d.requestId] = info; + return {requestHeaders: newHeaders}; + } +}, filter, ['blocking', 'requestHeaders']); - browser.webRequest.onHeadersReceived.addListener(d => { - if (!rIDs[d.requestId] || !d.responseHeaders) return; - const newHeaders = []; - for (const header of d.responseHeaders) { - if (header.name.toLowerCase() !== 'access-control-allow-origin') { - newHeaders.push(header); - } +browser.webRequest.onHeadersReceived.addListener(d => { + if (!rIDs[d.requestId] || !d.responseHeaders) return; + const newHeaders = []; + for (const header of d.responseHeaders) { + if (header.name.toLowerCase() !== 'access-control-allow-origin') { + newHeaders.push(header); } - newHeaders.push(acao); - return {responseHeaders: newHeaders}; - }, filter, ['blocking', 'responseHeaders']); + } + newHeaders.push(acao); + return {responseHeaders: newHeaders}; +}, filter, ['blocking', 'responseHeaders']); - browser.webRequest.onCompleted.addListener(d => { - if (rIDs[d.requestId]) { - rIDs[d.requestId].successes++; - console.debug( - `Privacy-Oriented Origin Policy: request #${d.requestId} successfully altered\n type: ${d.type}\n url: ${d.url}` - ); - delete rIDs[d.requestId]; - } - }, filter); - browser.webRequest.onErrorOccurred.addListener(d => { - if (rIDs[d.requestId]) { - rIDs[d.requestId].errors++; - console.debug( - `Privacy-Oriented Origin Policy: request #${d.requestId} resulted in an error\n type: ${d.type}\n url: ${d.url}` - ); - delete rIDs[d.requestId]; - } - }, filter); - browser.webRequest.onBeforeRedirect.addListener(d => { - if ( - rIDs[d.requestId] && - d.redirectUrl && - !d.redirectUrl.indexOf('data:') - ) delete rIDs[d.requestId]; - }, filter); -})(); +browser.webRequest.onCompleted.addListener(d => { + if (rIDs[d.requestId]) { + rIDs[d.requestId].successes++; + console.debug( + `Privacy-Oriented Origin Policy: request #${d.requestId} successfully altered\n type: ${d.type}\n url: ${d.url}` + ); + delete rIDs[d.requestId]; + } +}, filter); +browser.webRequest.onErrorOccurred.addListener(d => { + if (rIDs[d.requestId]) { + rIDs[d.requestId].errors++; + console.debug( + `Privacy-Oriented Origin Policy: request #${d.requestId} resulted in an error\n type: ${d.type}\n url: ${d.url}` + ); + delete rIDs[d.requestId]; + } +}, filter); +browser.webRequest.onBeforeRedirect.addListener(d => { + if ( + rIDs[d.requestId] && + d.redirectUrl && + !d.redirectUrl.indexOf('data:') + ) delete rIDs[d.requestId]; +}, filter); diff --git a/src/pages/misc.js b/src/pages/misc.js index c9a917f..db763da 100644 --- a/src/pages/misc.js +++ b/src/pages/misc.js @@ -1,11 +1,5 @@ 'use strict'; -function getElements(ids) { - const result = {}; - for (const id of ids) result[id] = document.getElementById(id); - return result; -} - const overriderx = /^([0-2])::?(\S+)$/; const exclusionrx = /^\s*(\S+)[ \t]+(\S+)\s*$/; diff --git a/src/pages/options.htm b/src/pages/options.htm index c03313a..d2a9895 100644 --- a/src/pages/options.htm +++ b/src/pages/options.htm @@ -3,10 +3,8 @@ - -
Global mode

This defines the main criteria for removing Origin headers. Both modes are safe, but the aggressive mode is less tolerant, therefore it causes more web content to break. The relaxed mode should break website functionality only very rarely.

@@ -111,5 +109,7 @@

+ + diff --git a/src/pages/options.js b/src/pages/options.js index 7f2b239..d05e0e5 100644 --- a/src/pages/options.js +++ b/src/pages/options.js @@ -1,47 +1,46 @@ 'use strict'; -var settings; -document.addEventListener('DOMContentLoaded', e => { - const ui = getElements([ - 'relaxed', 'aggressive', 'd1', 'd2', 'd3', 'd4', 'd5', 'exclusions', - 'overrides', 'rdExclusions', 'referers', 'save', 'saved' - ]); - const srt = document.getElementsByClassName('srt'); - browser.storage.local.get({ - d1: false, d2: false, d3: false, d4: false, d5: false - }).then(r => { - const cb = e => { - setTimeout(e => { - const val = {}; - val[e.target.id] = e.target.open; - browser.storage.local.set(val); - }, 500, e); - }; - for (const i in r) { - ui[i].open = r[i]; - ui[i].addEventListener('toggle', cb); - } - }); - browser.runtime.sendMessage(true).then(msg => { - settings = msg; - ui.exclusions.value = populateExclusions(msg.exclusions); - ui.overrides.value = populateOverrides(msg.overrides); - ui.relaxed.checked = msg.relaxed; - ui.aggressive.checked = !msg.relaxed; - ui.rdExclusions.checked = msg.rdExclusions; - ui.referers.checked = msg.referers; - for (const i in srt) srt[i].checked = msg.strictTypes[srt[i].id]; - }); + +const ui = document.getElementsByTagName('*'); + +browser.storage.local.get({ + d1: false, d2: false, d3: false, d4: false, d5: false +}).then(r => { + const cb = e => { + setTimeout(e => { + const val = {}; + val[e.target.id] = e.target.open; + browser.storage.local.set(val); + }, 500, e); + }; + for (const i in r) { + ui[i].open = r[i]; + ui[i].addEventListener('toggle', cb); + } +}); +browser.runtime.sendMessage(true).then(msg => { + ui.exclusions.value = populateExclusions(msg.exclusions); + ui.overrides.value = populateOverrides(msg.overrides); + ui.relaxed.checked = msg.relaxed; + ui.aggressive.checked = !msg.relaxed; + ui.rdExclusions.checked = msg.rdExclusions; + ui.referers.checked = msg.referers; + for (const i in ui) { + if (ui[i].className === 'srt') ui[i].checked = msg.strictTypes[ui[i].id]; + } ui.save.onclick = e => { + const changes = Object.assign({}, msg); ui.saved.textContent = '. . .'; ui.saved.className = 'shown'; - settings.exclusions = parseExclusions(ui.exclusions.value); - settings.overrides = parseOverrides(ui.overrides.value); - settings.relaxed = ui.relaxed.checked; - settings.rdExclusions = ui.rdExclusions.checked; - settings.referers = ui.referers.checked; - for (const i in srt) settings.strictTypes[srt[i].id] = srt[i].checked; + changes.exclusions = parseExclusions(ui.exclusions.value); + changes.overrides = parseOverrides(ui.overrides.value); + changes.relaxed = ui.relaxed.checked; + changes.rdExclusions = ui.rdExclusions.checked; + changes.referers = ui.referers.checked; + for (const i in ui) { + if (ui[i].className === 'srt') changes.strictTypes[ui[i].id] = ui[i].checked; + } browser.storage.sync.clear() - .then(browser.storage.local.set(settings)) + .then(browser.storage.local.set(changes)) .then(() => { ui.saved.textContent = 'Saved!'; setTimeout(() => { diff --git a/src/pages/popup.htm b/src/pages/popup.htm index 1871132..24c2a60 100644 --- a/src/pages/popup.htm +++ b/src/pages/popup.htm @@ -3,8 +3,6 @@ - -

@@ -42,5 +40,7 @@ + + diff --git a/src/pages/popup.js b/src/pages/popup.js index 6e2a688..1fabe7e 100644 --- a/src/pages/popup.js +++ b/src/pages/popup.js @@ -1,99 +1,95 @@ 'use strict'; -document.addEventListener('DOMContentLoaded', () => { - const ui = getElements([ - 'enabled', 'host', 'altered', 'errors', 'global', 'aggressive', - 'aggressiveL', 'relaxed', 'relaxedL', 'off', 'offL', 'wrench' - ]); - let red; - let green; - const updateCounters = msg => { - const altered = msg._successes + msg._errors; - if (altered && !green) { - green = true; - ui.altered.className += ' green'; - } - if (msg._errors && !red) { - red = true; - ui.errors.className += ' red'; - } - ui.altered.textContent = altered.toString(); - ui.errors.textContent = msg._errors.toString(); - }; - ui.wrench.addEventListener('click', e => { - browser.runtime.openOptionsPage(); +const ui = document.getElementsByTagName('*'); + +let red; +let green; +const updateCounters = msg => { + const altered = msg._successes + msg._errors; + if (altered && !green) { + green = true; + ui.altered.className += ' green'; + } + if (msg._errors && !red) { + red = true; + ui.errors.className += ' red'; + } + ui.altered.textContent = altered.toString(); + ui.errors.textContent = msg._errors.toString(); +}; +ui.wrench.addEventListener('click', e => { + browser.runtime.openOptionsPage(); +}); +browser.tabs.query({active: true, currentWindow: true}).then(tabs => { + const port = browser.runtime.connect(); + window.addEventListener('unload', function(event) { + port.disconnect(); }); - browser.tabs.query({active: true, currentWindow: true}).then(tabs => { - const port = browser.runtime.connect(); - window.addEventListener('unload', function(event) { - port.disconnect(); - }); - port.onMessage.addListener(msg => { - if (msg.hasOwnProperty('enabled')) { - ui.enabled.checked = msg.enabled; - if (msg.host) { - ui.host.textContent = msg.host; - updateCounters(msg); - ui.off.disabled = false; - ui.relaxed.disabled = false; - ui.aggressive.disabled = false; - delete ui.offL.className; - delete ui.relaxedL.className; - delete ui.aggressiveL.className; - if (msg.oIndex === -1 || msg.overrides[msg.oIndex].regex) ui.global.checked = true; - if (~msg.oIndex) { - const isRegex = msg.overrides[msg.oIndex].regex && ui.global.checked; - switch (msg.mode) { - case 0: - isRegex ? ui.offL.className = 'rxMatch' : ui.off.checked = true; - break; - case 1: - isRegex ? ui.relaxedL.className = 'rxMatch' : ui.relaxed.checked = true; - break; - case 2: - isRegex ? ui.aggressiveL.className = 'rxMatch' : ui.aggressive.checked = true; - } + port.onMessage.addListener(msg => { + if (msg.hasOwnProperty('enabled')) { + ui.enabled.checked = msg.enabled; + if (msg.host) { + ui.host.textContent = msg.host; + updateCounters(msg); + ui.off.disabled = false; + ui.relaxed.disabled = false; + ui.aggressive.disabled = false; + delete ui.offL.className; + delete ui.relaxedL.className; + delete ui.aggressiveL.className; + if (msg.oIndex === -1 || msg.overrides[msg.oIndex].regex) ui.global.checked = true; + if (~msg.oIndex) { + const isRegex = msg.overrides[msg.oIndex].regex && ui.global.checked; + switch (msg.mode) { + case 0: + isRegex ? ui.offL.className = 'rxMatch' : ui.off.checked = true; + break; + case 1: + isRegex ? ui.relaxedL.className = 'rxMatch' : ui.relaxed.checked = true; + break; + case 2: + isRegex ? ui.aggressiveL.className = 'rxMatch' : ui.aggressive.checked = true; } } - ui.enabled.onchange = e => { - browser.storage.local.set({enabled: ui.enabled.checked}); - }; - const cb = e => { - if (e.target.checked) { - const override = { - rule: msg.host, - mode: +e.target.value - }; - if (~msg.oIndex && msg.overrides[msg.oIndex].regex) { - browser.storage.local.set({ - overrides: [override].concat(msg.overrides) - }); - } else { - browser.storage.local.set({ - overrides: [override].concat(msg.overrides.filter((l,i) => { - return l && i !== msg.oIndex - })) - }); - } - } - }; - ui.off.onchange = cb; - ui.relaxed.onchange = cb; - ui.aggressive.onchange = cb; - ui.global.onchange = e => { - if (ui.global.checked && msg.oIndex !== -1) { + } + ui.enabled.onchange = e => { + browser.storage.local.set({enabled: ui.enabled.checked}); + }; + const cb = e => { + if (e.target.checked) { + const override = { + rule: msg.host, + mode: +e.target.value + }; + if (~msg.oIndex && msg.overrides[msg.oIndex].regex) { browser.storage.local.set({ - overrides: msg.overrides.filter((l,i) => { + overrides: [override].concat(msg.overrides) + }); + } else { + browser.storage.local.set({ + overrides: [override].concat(msg.overrides.filter((l,i) => { return l && i !== msg.oIndex - }) + })) }); } - }; - } else { - ui.host.textContent = msg.host; - updateCounters(msg); - } - }); - port.postMessage(tabs[0].id); + } + }; + ui.off.onchange = cb; + ui.relaxed.onchange = cb; + ui.aggressive.onchange = cb; + ui.global.onchange = e => { + if (ui.global.checked && msg.oIndex !== -1) { + browser.storage.local.set({ + overrides: msg.overrides.filter((l,i) => { + return l && i !== msg.oIndex + }) + }); + } + }; + } else { + ui.host.textContent = msg.host; + updateCounters(msg); + } }); + port.postMessage(tabs[0].id); });