Skip to content

Commit

Permalink
optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
claustromaniac committed Jan 17, 2019
1 parent fa354b0 commit 6cf97fd
Show file tree
Hide file tree
Showing 10 changed files with 281 additions and 286 deletions.
5 changes: 3 additions & 2 deletions src/bg/classes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions src/bg/globals.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict';

const settings = new Settings();
const popup = new Popup();
const tabs = new Tabs();
Expand Down
2 changes: 2 additions & 0 deletions src/bg/runtime.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict';

browser.runtime.onConnect.addListener(port => {
port.onMessage.addListener(msg => {
popup.start(msg, port);
Expand Down
2 changes: 2 additions & 0 deletions src/bg/tabs.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
'use strict';

browser.tabs.onRemoved.addListener((tabId, removeInfo) => { delete tabs[tabId] });
browser.tabs.onReplaced.addListener((newId, oldId) => { delete tabs[oldId] });
293 changes: 146 additions & 147 deletions src/bg/webRequest.js
Original file line number Diff line number Diff line change
@@ -1,157 +1,156 @@
(() => {
'use strict';
const acao = {name: 'Access-Control-Allow-Origin', value: '*'};
const filter = {urls: ["<all_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: ["<all_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);
6 changes: 0 additions & 6 deletions src/pages/misc.js
Original file line number Diff line number Diff line change
@@ -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*$/;

Expand Down
4 changes: 2 additions & 2 deletions src/pages/options.htm
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
<head>
<meta charset="utf-8">
<link href="options.css" rel="stylesheet">
<script src="misc.js"></script>
</head>
<body>
<script defer src="options.js"></script>
<fieldset>
<details id="d1" open><summary>Global mode</summary>
<p>This defines the main criteria for removing <code>Origin</code> 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.</p>
Expand Down Expand Up @@ -111,5 +109,7 @@
</details>
</fieldset><br>
<button class="browser-style" id="save">Save</button><span class="hidden" id="saved"></span>
<script src="misc.js"></script>
<script src="options.js"></script>
</body>
</html>
Loading

0 comments on commit 6cf97fd

Please sign in to comment.